var recLength = 0,

recBuffersL = [],
recBuffersR = [],
sampleRate;

this.onmessage = function(e){

switch(e.data.command){
  case 'init':
    init(e.data.config);
    break;
  case 'record':
    record(e.data.buffer);
    break;
  case 'exportWAV':
    exportWAV(e.data.type);
    break;
  case 'getBuffer':
    getBuffer();
    break;
  case 'clear':
    clear();
    break;
}

};

function init(config){

sampleRate = config.sampleRate;

}

function record(inputBuffer){

recBuffersL.push(inputBuffer[0]);
recBuffersR.push(inputBuffer[1]);
recLength += inputBuffer[0].length;

}

function exportWAV(type){

var bufferL = mergeBuffers(recBuffersL, recLength);
var bufferR = mergeBuffers(recBuffersR, recLength);
var interleaved = interleave(bufferL, bufferR);
var dataview = encodeWAV(interleaved);
var audioBlob = new Blob([dataview], { type: type });

this.postMessage(audioBlob);

}

function getBuffer() {

var buffers = [];
buffers.push( mergeBuffers(recBuffersL, recLength) );
buffers.push( mergeBuffers(recBuffersR, recLength) );
this.postMessage(buffers);

}

function clear(){

recLength = 0;
recBuffersL = [];
recBuffersR = [];

}

function mergeBuffers(recBuffers, recLength){

var result = new Float32Array(recLength);
var offset = 0;
for (var i = 0; i < recBuffers.length; i++){
  result.set(recBuffers[i], offset);
  offset += recBuffers[i].length;
}
return result;

}

function interleave(inputL, inputR){

var length = inputL.length + inputR.length;
var result = new Float32Array(length);

var index = 0,
  inputIndex = 0;

while (index < length){
  result[index++] = inputL[inputIndex];
  result[index++] = inputR[inputIndex];
  inputIndex++;
}
return result;

}

function floatTo16BitPCM(output, offset, input){

for (var i = 0; i < input.length; i++, offset+=2){
  var s = Math.max(-1, Math.min(1, input[i]));
  output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
}

}

function writeString(view, offset, string){

for (var i = 0; i < string.length; i++){
  view.setUint8(offset + i, string.charCodeAt(i));
}

}

function encodeWAV(samples){

var buffer = new ArrayBuffer(44 + samples.length * 2);
var view = new DataView(buffer);

/* RIFF identifier */
writeString(view, 0, 'RIFF');
/* RIFF chunk length */
view.setUint32(4, 36 + samples.length * 2, true);
/* RIFF type */
writeString(view, 8, 'WAVE');
/* format chunk identifier */
writeString(view, 12, 'fmt ');
/* format chunk length */
view.setUint32(16, 16, true);
/* sample format (raw) */
view.setUint16(20, 1, true);
/* channel count */
view.setUint16(22, 2, true);
/* sample rate */
view.setUint32(24, sampleRate, true);
/* byte rate (sample rate * block align) */
view.setUint32(28, sampleRate * 4, true);
/* block align (channel count * bytes per sample) */
view.setUint16(32, 4, true);
/* bits per sample */
view.setUint16(34, 16, true);
/* data chunk identifier */
writeString(view, 36, 'data');
/* data chunk length */
view.setUint32(40, samples.length * 2, true);

floatTo16BitPCM(view, 44, samples);

return view;

}