Mixing sounds bug *
Mixed/saved sound is distorted after couple of seconds...
How to fix it?
/**
* 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;
}
}