(function(self) {

  var min = Math.min,

      max = Math.max;



  var setString = function(view, offset, str) {

    var len = str.length;

    for (var i = 0; i < len; ++i)

      view.setUint8(offset + i, str.charCodeAt(i));

  };



  var Encoder = function(sampleRate, numChannels) {

    this.sampleRate = sampleRate;

    this.numChannels = numChannels;

    this.numSamples = 0;

    this.dataViews = [];

  };



  Encoder.prototype.encode = function(buffer) {

    var len = 1024;

    this.dataViews.push(buffer);

    this.numSamples += len;

  };



  Encoder.prototype.finish = function(mimeType) {

    var dataSize = this.numChannels * this.numSamples * 2,

        view = new DataView(new ArrayBuffer(44));

    setString(view, 0, 'RIFF');

    view.setUint32(4, 36 + dataSize, true);

    setString(view, 8, 'WAVE');

    setString(view, 12, 'fmt ');

    view.setUint32(16, 16, true);

    view.setUint16(20, 1, true);

    view.setUint16(22, this.numChannels, true);

    view.setUint32(24, this.sampleRate, true);

    view.setUint32(28, this.sampleRate * 4, true);

    view.setUint16(32, this.numChannels * 2, true);

    view.setUint16(34, 16, true);

    setString(view, 36, 'data');

    view.setUint32(40, dataSize, true);

    this.dataViews.unshift(view);

    var blob = new Blob(this.dataViews, { type: 'audio/wav' });

    this.cleanup();

    return blob;

  };



  Encoder.prototype.cancel = Encoder.prototype.cleanup = function() {

    delete this.dataViews;

  };



  self.WavAudioEncoder = Encoder;

})(self);