<p>
<div id="file"></div>
<button id="play" onClick="play()">play</button>
<a id="download" target="_blank">ダウンロード</a>
</p>
<p>
f <input id="f" type="text" size="10" value="" onInput="return change_f();"/>
r <input id="r" type="text" size="10" value="" onInput="return change_r();"/>
B <input id="B" type="text" size="10" value="" onInput="return change_B();"/>
</p>
<div id="freq"></div>
<div id="rezo"></div>
<div id="gain"></div>
<div id="disp" type="text"></div>
var S = 2;
var C = 2;

newaudio();

var context1 = new AudioContext();
var mediaSourceNode1 = new Array(S);
for (var s = 0; s < S; s++){
mediaSourceNode1[s] = context1.createMediaElementSource(document.getElementById("audio_player"+s));
}

// createIIRFilter ... not found 160214 chrome, Firefox
var Nframe=4096;
var NDFT = 1024;
var r = 0.999;
document.getElementById("r").value = r;
var rpow2 = Math.pow(r,2);
var rpowN = Math.pow(r,NDFT);
var slidingGoertzelDFTP1 = new Array(S);
for (var s = 0; s < S; s++){
  slidingGoertzelDFTP1[s] = context1.createScriptProcessor(Nframe, C, C);
  slidingGoertzelDFTP1[s].s = s;
  slidingGoertzelDFTP1[s].buf = new Array(C);
  for (var c = 0; c < C; c++){
    slidingGoertzelDFTP1[s].buf[c] = new Float32Array(NDFT+1);
    for (var n = 0; n < NDFT; n++){slidingGoertzelDFTP1[s].buf[c][n] = 0;}
  }

  slidingGoertzelDFTP1[s].onaudioprocess = function(audioProcessingEvent) {
    var s = this.s;
    var inputBuffer = audioProcessingEvent.inputBuffer;
    var outputBuffer = audioProcessingEvent.outputBuffer;
    for (var c = 0; c < C; c++){
      var inputData = inputBuffer.getChannelData(c);
      var outputData = outputBuffer.getChannelData(c);
      var n = 0; 
      for (; n < NDFT; n++){outputData[n] = (inputData[n] - this.buf[c][n]*rpowN)/NDFT;}
      for (; n < Nframe-NDFT; n++){outputData[n] = (inputData[n] - inputData[n-NDFT]*rpowN)/NDFT;}
      for (var n2 = 0; n < Nframe; n++, n2++){outputData[n] = (inputData[n] - inputData[n-NDFT]*rpowN)/NDFT;
        this.buf[c][n2]=inputData[n];}
    }
  };
}

var Bmax = 16;
var B = Bmax;
var Fs = 44100;
var kstep = 1 / (Fs / NDFT);
var f = Fs / NDFT;
document.getElementById("f").value = f;
var k = f * kstep * 16;
var slidingGoertzelDFTP2 = new Array(S);
for (var s = 0; s < S; s++){
slidingGoertzelDFTP2[s] = new Array(B);
for (var b = 0; b < B; b++){
slidingGoertzelDFTP2[s][b] = context1.createScriptProcessor(Nframe, C, C);
slidingGoertzelDFTP2[s][b].s = s;
slidingGoertzelDFTP2[s][b].b = b;
slidingGoertzelDFTP2[s][b].r = r;
slidingGoertzelDFTP2[s][b].k = k;
slidingGoertzelDFTP2[s][b].coef = 2*Math.cos(2*Math.PI*k/NDFT);
slidingGoertzelDFTP2[s][b].rpow2 = rpow2;
slidingGoertzelDFTP2[s][b].buf = new Array(C);
for (var c = 0; c < C; c++){
slidingGoertzelDFTP2[s][b].buf[c] = new Float32Array(2);
for (var t = 0; t < 2; t++){slidingGoertzelDFTP2[s][b].buf[c][t] = 0;}
}
slidingGoertzelDFTP2[s][b].onaudioprocess = function(audioProcessingEvent) {
  var s = this.s;
  var b = this.b;
  var inputBuffer = audioProcessingEvent.inputBuffer;
  var outputBuffer = audioProcessingEvent.outputBuffer;
  var r = this.r;
  var rpow2 = this.rpow2;
  var coef = this.coef;
  var buf;
  for (var c = 0; c < C; c++){
  var inputData = inputBuffer.getChannelData(c);
  var outputData = outputBuffer.getChannelData(c);
    for (var n = 0; n < Nframe; n++){
      buf = inputData[n] + coef*this.buf[c][0]*r - this.buf[c][1]*rpow2;
      outputData[n] = buf*2 - coef*this.buf[c][0]*r;
      this.buf[c][1] = this.buf[c][0];
      this.buf[c][0] = buf;
    }
  }
};
}
}

var slidingGoertzelDFTG1 = new Array(S);
for (var s = 0; s < S; s++){
slidingGoertzelDFTG1[s] = new Array(B);
for (var b = 0; b < B; b++){
slidingGoertzelDFTG1[s][b] = context1.createGain();
slidingGoertzelDFTG1[s][b].gain.value = 0.0;
}
}




var audioData = [];
var logger = context1.createScriptProcessor(Nframe, C, C);
logger.onaudioprocess = function(audioProcessingEvent) {
  var inputBuffer = audioProcessingEvent.inputBuffer;
  var inputData = new Array(C);
  var bufferData = new Float32Array(Nframe*C);
  var c;
  for (c = 0; c < C; c++){inputData[c] = inputBuffer.getChannelData(c); }
  var n_buffer = 0;
  for (var n = 0; n < Nframe; n++){
    for (c = 0; c < C; c++){
      bufferData[n_buffer] = inputData[c][n];
      n_buffer++;
    }
  }
  audioData.push(bufferData);
}



// connect nodes
for (var s = 0; s < S; s++){
mediaSourceNode1[s].connect(slidingGoertzelDFTP1[s]);
}

for (var s = 0; s < S; s++){
for (var b = 0; b < B; b++){
slidingGoertzelDFTP1[s].connect(slidingGoertzelDFTP2[s][b]);
}
}

for (var s = 0; s < S; s++){
for (var b = 0; b < B; b++){
slidingGoertzelDFTP2[s][b].connect(slidingGoertzelDFTG1[s][b]);
}
}

var merger = context1.createGain();
for (var s = 0; s < S; s++){
for (var b = 0; b < B; b++){
slidingGoertzelDFTG1[s][b].connect(merger);
}
}

merger.connect(logger);


// set default B
B = 3;
document.getElementById("B").value = B;


function change_r() {
var r_buf = Math.min(Math.max(parseFloat(document.getElementById("r").value), -1.0),1.0); 
if (isNaN(r_buf)){}
else{
r = r_buf;
rpow2 = Math.pow(r,2);
rpowN = Math.pow(r,NDFT);
for (var b = 0; b < B; b++){
document.getElementById("rezo"+"_"+b).value = r;
document.getElementById("rezo"+"_"+b).oninput();
}
}
};
function change_f() {
var k_buf = parseFloat(document.getElementById("f").value) * kstep;
if (isNaN(k_buf)){}
else{
f = parseFloat(document.getElementById("f").value);
k = k_buf;
for (var b = 0; b < B; b++){
document.getElementById("freq"+"_"+b).value = f + b * Fs / NDFT;
document.getElementById("freq"+"_"+b).oninput();
}
}
};
function change_B() {
var B_buf = Math.min(Math.max(parseInt(document.getElementById("B").value), 0),Bmax); 
// NaNの判定について
// http://qiita.com/south37/items/e400a3a698957ab4aa7a
if (B_buf === B_buf) {
B = B_buf;
removeinputformsset();
newinputformsset();
// mute unuse nodes
for (var s = 0; s < S; s++){
for (var b = B; b < Bmax; b++){
slidingGoertzelDFTG1[s][b].gain.value = 0.0;
}
}
}
};



var exportWAV = function(audioData) {
  var encodeWAV = function(samples, sampleRate) {
    var buffer = new ArrayBuffer(44 + samples.length * 2);
    var view = new DataView(buffer);

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

    var floatTo16BitPCM = function(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);
      }
    };

    writeString(view, 0, 'RIFF');                     // RIFF header
    view.setUint32(4, 32 + samples.length * 2, true); // number of bytes of hereafter
    writeString(view, 8, 'WAVE');                     // WAVE header
    writeString(view, 12, 'fmt ');                    // fmt chunk
    view.setUint32(16, 16, true);                     // number of bytes of fmt chunk
    view.setUint16(20, 1, true);                      // format ID
    view.setUint16(22, C, true);                      // number of channels
    view.setUint32(24, sampleRate, true);             // sampling rate
    view.setUint32(28, sampleRate * 2, true);         // data rate
    view.setUint16(32, 2, true);                      // block size
    view.setUint16(34, 16, true);                     // number of bits par sample
    writeString(view, 36, 'data');                    // data chunk
    view.setUint32(40, samples.length * 2, true);     // number of bytes of wave form
    floatTo16BitPCM(view, 44, samples);               // wave form

    return view;
  };

  var mergeBuffers = function(audioData) {
    var sampleLength = 0;
    for (var i = 0; i < audioData.length; i++) {
      sampleLength += audioData[i].length;
    }
    var samples = new Float32Array(sampleLength);
    var sampleIdx = 0;
    for (var i = 0; i < audioData.length; i++) {
      for (var j = 0; j < audioData[i].length; j++) {
        samples[sampleIdx] = audioData[i][j];
        sampleIdx++;
      }
    }
    return samples;
  };

  var dataview = encodeWAV(mergeBuffers(audioData), context1.sampleRate);
  var audioBlob = new Blob([dataview], { type: 'audio/wav' });

  var myURL = window.URL || window.webkitURL;
  var url = myURL.createObjectURL(audioBlob);
  return url;
};

var disconnect_margin = 500; //100; // msec

function onended(){
  setTimeout(
    function(){
      merger.disconnect(context1.destination);
      logger.disconnect(context1.destination);
      var outblob = exportWAV(audioData); 
      var download = document.getElementById('download');
      download.href=outblob; console.log(outblob);
    }, disconnect_margin);
}


function play(){
  var files = new Array(S);
  var flagplayable = false;
  for (var s = 0; s < S; s++) {
    var audiofile = document.getElementById("audio_file"+s);
      files[s] = audiofile.files;
      if (files[s].length != 0) {flagplayable = true;}
    }
  if(flagplayable == true){
    audioData = [];
    merger.connect(context1.destination);
    logger.connect(context1.destination);
  }
  
  for (var s = 0; s < S; s++) {
    if(files[s].length == 0){ console.log("files"+s+" : null"); }
    else{
      var file1 = URL.createObjectURL(files[s][0]); 
      console.log("File" + s + " : " + file1);
      var audio_player1 = document.getElementById("audio_player"+s);
      audio_player1.src = file1;
      audio_player1.play();
      
      audio_player1.onended = function(){
        for (var s = 0; s < S; s++) {
          if (s == this.s) {this.onended = null;}
          else {var audio_player2 = document.getElementById("audio_player"+s);
          if (audio_player2.onended == null) {onended();}
          }
        }
      }
    } 
  }
};





function changeforms(id) {
var forms = document.getElementById(id);
var s = document.getElementById(id).getAttribute("s");
var b = document.getElementById(id).getAttribute("b");
for (var s = 0; s < S; s++) {
slidingGoertzelDFTG1[s][b].gain.value = document.getElementById(id).value;
}
document.getElementById("disp").innerHTML = "id : "+id+" has been changed " + document.getElementById(id).value;
};
function changeformsgain(id) {
var gain = parseFloat(document.getElementById(id).value);
if (isNaN(gain)){}
else{
var forms = document.getElementById(id);
var s = document.getElementById(id).getAttribute("s");
var b = document.getElementById(id).getAttribute("b");
for (var s = 0; s < S; s++) {
slidingGoertzelDFTG1[s][b].gain.value = gain;
}
document.getElementById("disp").innerHTML = "id : "+id+" has been changed " + gain;
}
};
function changeformsfreq(id) {
var freq = parseFloat(document.getElementById(id).value);
if (isNaN(freq)){}
else{
var forms = document.getElementById(id);
var s = document.getElementById(id).getAttribute("s");
var b = document.getElementById(id).getAttribute("b");
var k = freq * kstep;
for (var s = 0; s < S; s++) {
slidingGoertzelDFTP2[s][b].k = k;
slidingGoertzelDFTP2[s][b].coef = 2*Math.cos(2*Math.PI*k/NDFT);
}
document.getElementById("disp").innerHTML = "id : "+id+" has been changed " + freq;
}
};
function changeformsrezo(id) {
var r = Math.min(Math.max(parseFloat(document.getElementById(id).value), -1.0),1.0); 
if (isNaN(r)){}
else{
var forms = document.getElementById(id);
var s = document.getElementById(id).getAttribute("s");
var b = document.getElementById(id).getAttribute("b");
for (var s = 0; s < S; s++) {
slidingGoertzelDFTP2[s][b].r = r;
slidingGoertzelDFTP2[s][b].rpow2 = Math.pow(r,2);
}
document.getElementById("disp").innerHTML = "id : "+id+" has been changed " + r;
}
};
function newinputforms(hoge, key, N, a0=0, an=1) {
var form = document.createElement("form");
hoge.appendChild(form);
var title = document.createElement("text");
form.appendChild(title);
title.setAttribute("id", key+"_"+"title");
title.innerHTML = key;
title.style = "width:36px";
var forms = new Object;
for (var n = 0; n < N; n++){
forms[n] = document.createElement("input");
forms[n].setAttribute("type","text");
forms[n].setAttribute("id",key+"_"+n);
forms[n].setAttribute("name","inputform"+"_"+key+"_"+n);
forms[n].setAttribute("value",a0+an*n);
forms[n].setAttribute("onInput","changeforms"+key+"(this.id)");
forms[n].setAttribute("s",0);
forms[n].setAttribute("b",n);
form.appendChild(forms[n]);
document.getElementById(key+"_"+n).oninput();
}
};

function newaudio() {
var hoge = document.getElementById("file");
var audios = new Object;
for (var s = 0; s < S; s++){
audios[s] = document.createElement("div");
audios[s].innerHTML = "File"+s+" <input id=\"audio_file"+s+"\" type=\"file\" accept=\"audio/*\" />"+"<audio id=\"audio_player"+s+"\"></audio>";
hoge.appendChild(audios[s]);
var audiofile = document.getElementById("audio_file"+s);
audiofile.s = s;
audiofile.onchange = function(){
    var files = this.files;
    var file = URL.createObjectURL(files[0]); 
    document.getElementById("audio_player"+this.s).src = file;
};
document.getElementById("audio_player"+s).s = s;
}
};

function newinputformsset() {
var gain = document.getElementById("gain");
newinputforms(gain, "gain", B, 1, 0);
var freq = document.getElementById("freq");
newinputforms(freq, "freq", B, f, Fs / NDFT);
//newinputforms(freq, "freq", B, f, f);
var rezo = document.getElementById("rezo");
newinputforms(rezo, "rezo", B, r, 0);
};
function removeinputformsset() {
var node;
var gain = document.getElementById("gain");
node = gain.childNodes[0];
gain.removeChild(node);
var freq = document.getElementById("freq");
node = freq.childNodes[0];
freq.removeChild(node);
var rezo = document.getElementById("rezo");
node = rezo.childNodes[0];
rezo.removeChild(node);
};
window.onload = function(){
newinputformsset();
};
Rerun