package com.increpare.bfxr.synthesis
{
import flash.utils.*;
public class WaveWriter {
public var outBuffer:ByteArray;
private var stereo:Boolean=true;
private const sampleRate:uint=44100;
private var bitsPerSample:uint=32;
private var useFloat:Boolean=true;
private var writePointer:uint;
private var riffSizePointer:uint, dataSizePointer:uint, factSamplesPointer:uint;
public function WaveWriter(stereo:Boolean,bits:uint=32,b:ByteArray=null) {
this.stereo=stereo;
bitsPerSample=bits;
useFloat=bits>=32;
if(b) {
outBuffer=b;
} else {
outBuffer=new ByteArray();
}
writeWAVEHeader();
}
private function writeWAVEHeader():void {
outBuffer.endian=Endian.BIG_ENDIAN;
outBuffer.writeUnsignedInt(0x52494646);
riffSizePointer=outBuffer.position;
outBuffer.writeUnsignedInt(0);
outBuffer.writeUnsignedInt(0x57415645);
outBuffer.writeUnsignedInt(0x666D7420);
outBuffer.endian=Endian.LITTLE_ENDIAN;
var bytesPerSample:uint=bitsPerSample/8;
var blockSize:uint=(stereo+1)*bytesPerSample;
outBuffer.writeUnsignedInt((useFloat?(22+2):0)+16); outBuffer.writeShort(useFloat?0xFFFE:1); outBuffer.writeShort(stereo+1); outBuffer.writeUnsignedInt(sampleRate); outBuffer.writeUnsignedInt(sampleRate*blockSize); outBuffer.writeShort(blockSize); outBuffer.writeShort(bitsPerSample);
if(useFloat) {
outBuffer.writeShort(22); outBuffer.writeShort(bitsPerSample); outBuffer.writeUnsignedInt(3);
outBuffer.writeUnsignedInt(0x0003);
outBuffer.writeShort(0x0000); outBuffer.writeShort(0x0010);
outBuffer.writeByte(0x80);
outBuffer.writeByte(0x00);
outBuffer.writeByte(0x00);
outBuffer.writeByte(0xaa);
outBuffer.writeByte(0x00);
outBuffer.writeByte(0x38);
outBuffer.writeByte(0x9b);
outBuffer.writeByte(0x71);
outBuffer.endian=Endian.BIG_ENDIAN;
outBuffer.writeUnsignedInt(0x66616374); outBuffer.endian=Endian.LITTLE_ENDIAN;
outBuffer.writeUnsignedInt(4); factSamplesPointer=outBuffer.position
outBuffer.writeUnsignedInt(1); }
outBuffer.endian=Endian.BIG_ENDIAN;
outBuffer.writeUnsignedInt(0x64617461); outBuffer.endian=Endian.LITTLE_ENDIAN;
dataSizePointer=outBuffer.position;
outBuffer.writeUnsignedInt(0);
writePointer=outBuffer.position;
}
public function finalize(): void {
if( dataLength % 2 == 1) { outBuffer.position=writePointer;
outBuffer.writeByte(0);
writePointer=outBuffer.position;
}
updateSizeFields();
}
/** position difference from begining of data tag to end of data,
not counting the size field itself
*/
private function get dataLength():uint {
return writePointer-(dataSizePointer+4);
}
public function updateSizeFields():void {
var sampleByteLength:uint=dataLength;
outBuffer.endian=Endian.LITTLE_ENDIAN;
outBuffer.position=riffSizePointer;
outBuffer.writeUnsignedInt(outBuffer.length-8);
if(useFloat) {
outBuffer.position=factSamplesPointer;
outBuffer.writeUnsignedInt(sampleByteLength/(bitsPerSample/8));
}
outBuffer.position=dataSizePointer;
outBuffer.writeUnsignedInt(sampleByteLength);
}
public function addSamples(sb:ByteArray):void {
outBuffer.position=writePointer;
outBuffer.endian=Endian.LITTLE_ENDIAN;
if(stereo && useFloat && bitsPerSample==32 && sb.endian==Endian.LITTLE_ENDIAN) {
outBuffer.writeBytes(sb);
} else if(stereo) {
while(sb.position<sb.length) {
var left:Number=sb.readFloat();
var right:Number=sb.readFloat();
if(useFloat) {
if(bitsPerSample==32) {
outBuffer.writeFloat(left);
outBuffer.writeFloat(right);
} else { outBuffer.writeDouble(left);
outBuffer.writeDouble(right);
}
} else {
if(bitsPerSample==8) {
outBuffer.writeByte(numberTo8bit(left));
outBuffer.writeByte(numberTo8bit(right));
} else { outBuffer.writeShort(numberTo16bit(left));
outBuffer.writeShort(numberTo16bit(right));
}
} } } else { while(sb.position<sb.length) {
left=sb.readFloat();
if(useFloat) {
if(bitsPerSample==32) {
outBuffer.writeFloat(left);
} else { outBuffer.writeDouble(left);
}
} else {
if(bitsPerSample==8) {
outBuffer.writeByte(numberTo8bit(left));
} else { outBuffer.writeShort(numberTo16bit(left));
}
} } } writePointer=outBuffer.position;
}
public static function numberTo8bit(x:Number):uint {
return x*128+127;
}
public static function numberTo16bit(x:Number):uint {
return int(x * 32767 +0.5);
}
}
}