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

Mixing sounds bug *

Mixed/saved sound is distorted after couple of seconds...
How to fix it?
Get Adobe Flash player
by djankey 28 Oct 2011

    Talk

    djankey at 27 Oct 2011 18:57
    Mixed/saved sound is distorted after couple of seconds... How to fix it?
    djankey at 29 Oct 2011 05:41
    Fixed: http://wonderfl.net/c/sUqx

    Tags

    Embed
/**
 * Copyright djankey ( http://wonderfl.net/user/djankey )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/gyTW
 */

package {
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.SampleDataEvent;
    import flash.events.MouseEvent;
    import flash.net.FileReference;       
    import flash.net.URLRequest;
    import flash.media.Sound;
    import flash.media.SoundChannel;
    import flash.media.SoundTransform;
    import flash.utils.ByteArray;       
    import com.bit101.components.PushButton;
    import com.bit101.components.Label;
    
    public class FlashTest extends Sprite {
        private var len:int = 6;
        private var loaded:int = 0;
        private var buttons:Array = new Array();        
        private var sounds:Array = new Array();
        private var channels:Array = new Array();
        private var buffers:Array = new Array();
        private var playing:Array = new Array();
        
        private static const BUFFER_SIZE:uint = 8192;
        private var output:Sound;
        private var outputChannel:SoundChannel;
        private var outputPosition:Number = 0;        
        private var outputTrack:ByteArray;
        
        private var lbl:Label;
        private var labels:Array = new Array();
        private var rec:PushButton;
        private var mousePressed:Boolean = false;
        private var recording:Boolean = false;
        private var file:FileReference = new FileReference();      
        private var path:String = "http://www.as-flash.com/temp/sounds/";
                
        public function FlashTest() {
            // write as3 code here..
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);           
        }
        
        //________________________________________________________ Create buttons and load sounds
        private function init(e:Event = null):void
        {
           // label
           lbl = new Label(this, 0,0, "loading sounds:" + loaded + " / " + len);
          
           
           // load
           for(var i:int=0;i<len;i++) {             
               sounds[i] = new Sound();              
               sounds[i].load(new URLRequest(path + (i+1) + ".mp3"));
               sounds[i].addEventListener(Event.COMPLETE, soundLoaded);
           }         
        }
        
        // sound loaded
        private function soundLoaded(event:Event):void
        { 
            loaded++;
            lbl.text = "loading sounds:" + loaded + " / " + len;
            if (loaded == len) go();       
        }
        
        //________________________________________________________ All sounds loaded
        private function go():void
        { 
           lbl.text = "Press REC and start recording your mix";
           
           // output
           output = new Sound();
           outputChannel  = new SoundChannel();
           outputTrack = new ByteArray();           
           
           // setup buttons...
           for(var i:int=0;i<len;i++){
               var btn:PushButton = new PushButton(this, 0, 50 + i*22, "sound " + (i+1));
               btn.addEventListener(MouseEvent.MOUSE_DOWN, btnDown);            
               btn.addEventListener(MouseEvent.MOUSE_OUT, btnOut);            
               btn.addEventListener(MouseEvent.MOUSE_OVER, btnOver);
               buttons[i] = btn;
               
               channels[i] = null;
               buffers[i] = new ByteArray();
               playing[i] = false;
               
               labels[i] = new Label(this, 120, 50 + i*22, "/");               
           }           
           
           // record button
           rec = new PushButton(this, 0, 100+len*22, "REC", record);
           
           // info
           var info:Label = new Label(this, 0, 300, "Try to record more than 3 seconds of sounds (play it like guitar) and then listen saved mix.\nSamples written to the ByteArray are 0 if you keep pressing same button.\nHow to fix this bug?");
           
           // samples info
           var samplesInfo:Label = new Label(this, 112, 28, "samples written to the ByteArray");
           
           // mouse down    
           stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDown);
           stage.addEventListener(MouseEvent.MOUSE_UP, mouseUp);
       }
       
       //________________________________________________________ mouse pressed?
        private function mouseDown(event:MouseEvent = null):void        
        {
            mousePressed = true;
        }
        private function mouseUp(event:MouseEvent = null):void        
        {
            mousePressed = false;
        } 
        
        //________________________________________________________ buttons actions
       private function btnDown(event:MouseEvent):void
        {
            var id:int = getButtonID(event.currentTarget);
            buttons[id].alpha = 0.5;
            playSound(id);
        }
        
        private function btnOut(event:MouseEvent):void
        {
            var id:int = getButtonID(event.currentTarget);
            buttons[id].alpha = 1;           
        }
        
        private function btnOver(event:MouseEvent):void
        {            
            if (mousePressed == true) {
               var id:int = getButtonID(event.currentTarget);
               buttons[id].alpha = 0.8;
               playSound(id);
            } 
        }
        
        private function getButtonID(btn:Object):int
        {
           var id:int = -1;
           for(var i:int=0;i<len;i++){
               if(btn == buttons[i]){
                   id = i;
                   break;
               } 
           }
           return id;
        }
       
       //________________________________________________________ Play sound
       private function playSound(id:int):void       
       {
            if(channels[id]!=null){
                channels[id].removeEventListener(Event.SOUND_COMPLETE, soundComplete);
                channels[id].stop();
            }
           
            channels[id] = sounds[id].play(0);
            channels[id].addEventListener(Event.SOUND_COMPLETE, soundComplete);
            playing[id] = true;
        }
        
        //________________________________________________________ Sound complete
        private function soundComplete(event:Event):void
        {
            var id:int = -1;           
            for(var i:int=0;i<len;i++){
                if(channels[i] == event.target){
                    id = i;
                    break;
                } 
            }
             
            if(id>-1){               
              if(channels[id]!=null){
                channels[id].removeEventListener(Event.SOUND_COMPLETE, soundComplete);
                channels[id].stop();
              }
              playing[id] = false;             
            }            
        }

       //________________________________________________________ record button pressed
       private function record(event:MouseEvent):void
       {
           if(recording) {
               lbl.text = "Record your mix";
               rec.label  = "REC";     
               recording = false;
               outputPosition = outputChannel.position;
               outputChannel.stop();
               output.removeEventListener(SampleDataEvent.SAMPLE_DATA , onSoundData);              
               saveMixedTrack();
           } else{       
               lbl.text = "Recording...";    
               rec.label  = "SAVE MIX";
               recording = true;
               output.addEventListener(SampleDataEvent.SAMPLE_DATA , onSoundData );                
               outputChannel = output.play(outputPosition);                
               outputChannel.soundTransform = new SoundTransform(0);
           }        
       }
              
       //________________________________________________________ Sound data
       private function onSoundData(sampleDataEvent:SampleDataEvent) : void
      {
          var lengths:Array = new Array();       
          
          // read
          for(var i:int=0;i<len;i++){
              lengths[i] = "/";
              
              if(playing[i]==true && channels[i]!=null){
                  buffers[i].position = 0;
                  lengths[i] = sounds[i].extract(buffers[i], BUFFER_SIZE);
                  buffers[i].position = 0;
              }
              
              labels[i].text = String(lengths[i]);
          }           
           
          
          // write
          for(var j:int=0; j<BUFFER_SIZE; j++){                          
              var left:Number = 0;
              var right:Number = 0; 
              for(var k:int=0; k<len; k++){
                  if (playing[k]==true) {
                      left += buffers[k].readFloat();   
                      right += buffers[k].readFloat();
                  }                      
              }
              
              // buffers[k].bytesAvailable ?
              
              sampleDataEvent.data.writeFloat(left);
              sampleDataEvent.data.writeFloat(right);
              outputTrack.writeFloat(left);
              outputTrack.writeFloat(right);
          }          
      } 
       
       //________________________________________________________ Save sound
       private function saveMixedTrack():void
       {
          var encodedBA:ByteArray = FxWaveEncoder.encoder(outputTrack);
          file.save(encodedBA, "mix.wav");
          lbl.text = "Record your mix";
       }
    }
}



// Wav encoder
// http://www.ceteris-paribus.info/article-29893316.html
import flash.utils.Endian;
import flash.utils.ByteArray;   
import flash.events.Event;

class FxWaveEncoder
    {       
        // writeHeader ( 2, 16, 44100 )
        static public function encoder( pSamples:ByteArray, channels:int = 2, bits:int = 16, rate:int = 44100 ):ByteArray
        {
            var samples:ByteArray = new ByteArray();           
            samples.writeBytes( FxWaveEncoder.convert( pSamples ) );
            var bytes: ByteArray = new ByteArray();           
            bytes.endian = Endian.LITTLE_ENDIAN;           
            bytes.writeUTFBytes( 'RIFF' );           
            bytes.writeInt( samples.length - 8 );           
            bytes.writeUTFBytes( 'WAVE' );           
            bytes.writeUTFBytes( 'fmt ' );           
            bytes.writeInt( int( 16 ) );           
            bytes.writeShort( int( 1 ) );           
            bytes.writeShort( channels );           
            bytes.writeInt( rate );           
            bytes.writeInt( int( rate * channels * ( bits / 8 ) ) );           
            bytes.writeShort( int( channels * ( bits / 8 ) ) );           
            bytes.writeShort( bits );           
            bytes.writeUTFBytes( 'data' );           
            bytes.writeInt( samples.length - 44 );           
            bytes.writeBytes( samples );           
            bytes.position = 0;           
            return bytes;
        }
        
        static private function convert( pBytes:ByteArray ):ByteArray
        {
            var ba:ByteArray = new ByteArray ( ) ;           
            ba.endian = Endian.LITTLE_ENDIAN;           
            pBytes.position = 0;           
            while( pBytes.position < pBytes.length ) ba.writeShort( pBytes.readFloat() * 32767 );           
            return ba;
        }
    }