import processing.core.*; 
import processing.data.*; 
import processing.event.*; 
import processing.opengl.*; 

import java.io.*; 
import java.awt.FileDialog; 
import java.awt.Frame; 

import java.util.HashMap; 
import java.util.ArrayList; 
import java.io.File; 
import java.io.BufferedReader; 
import java.io.PrintWriter; 
import java.io.InputStream; 
import java.io.OutputStream; 
import java.io.IOException; 

public class kernelConvolver extends PApplet {






public void setup() {
  String[] params = loadStrings(sketchPath("params.txt"));
  WavFile baseFileA = WavFile.readFromFilePath(sketchPath(params[1]));
  WavFile baseFileB = WavFile.readFromFilePath(sketchPath(params[3]));
  float[][] waveFormA = baseFileA.samplesAsFloat();
  float[][] waveFormB = baseFileB.samplesAsFloat();
  float[][] newWaveForm = new float[2][max(waveFormA[0].length, waveFormB[0].length)];
  int kernelLength=Integer.parseInt(params[5]);
  int kernelCenter=floor((float)kernelLength/2);
  int blockSizeA=Integer.parseInt(params[7]);
  int blockSizeB=Integer.parseInt(params[9]);
  float[] window = new float[kernelLength];
  for (int k=0;k<kernelLength;k++) {
    float position = (float)(k-kernelCenter)/kernelCenter;
    window[k] = 1.369982685f*cos(position) + 0.4054102674f*cos(2*position) - 0.03542758202f*cos(3*position);// Nuttall window
  }
  for (int c=0;c<newWaveForm.length;c++) {
    for (int s=0;s<newWaveForm[c].length;s++) {
      newWaveForm[c][s] = 0;
      for (int k=0;k<kernelLength;k++) {
        int thisChA = c%waveFormA.length;
        int sPosAA = floor((float)s/blockSizeA)*blockSizeA;
        int sPosAB = sPosAA+blockSizeA;
        float blockPosA = (float)(s-sPosAA)/blockSizeA;
        float sampleAA = waveFormA[thisChA][(sPosAA+k-kernelCenter+waveFormA[thisChA].length)%waveFormA[thisChA].length];
        float sampleAB = waveFormA[thisChA][(sPosAB+k-kernelCenter+waveFormA[thisChA].length)%waveFormA[thisChA].length];
        float sampleA = sampleAA*(1-blockPosA) + sampleAB*blockPosA;
        int thisChB = c%waveFormB.length;
        int sPosBA = floor((float)s/blockSizeB)*blockSizeB;
        int sPosBB = sPosBA+blockSizeB;
        float blockPosB = (float)(s-sPosBA)/blockSizeB;
        float sampleBA = waveFormB[thisChB][(sPosBA+k-kernelCenter+waveFormB[thisChB].length)%waveFormB[thisChB].length];
        float sampleBB = waveFormB[thisChB][(sPosBB+k-kernelCenter+waveFormB[thisChB].length)%waveFormB[thisChB].length];
        float sampleB = sampleBA*(1-blockPosB) + sampleBB*blockPosB;
        newWaveForm[c][s] += sampleA * sampleB * window[k];
      }
    }
  }
  float highest=0;
  for (int c=0;c<newWaveForm.length;c++) {
    for (int i=0;i<newWaveForm[c].length;i++) highest=max((float)highest, abs((float)newWaveForm[c][i]));
  }
  for (int c=0;c<newWaveForm.length;c++) {
    for (int i=0;i<newWaveForm[c].length;i++) newWaveForm[c][i]=newWaveForm[c][i]/highest;
  }
  baseFileA.setSamplesFromFloat(newWaveForm);
  baseFileA.writeToFilePath(sketchPath("result.wav"));
}

public void draw() {
}


public float vrMax(float a, float b, float m) {
  float d1=b-a;
  if (d1>m/2) {
    d1=d1-m;
  }
  if (d1<-m/2) {
    d1=d1+m;
  }
  return d1;
}

public String getDialogFileUrl(String label) {
  Frame frame = new Frame();
  FileDialog fileDialog = new FileDialog(frame, label, FileDialog.LOAD);
  fileDialog.setVisible(true);
  if (fileDialog.getFile()!=null) {
    String filePath = fileDialog.getDirectory() + fileDialog.getFile();
    return filePath;
  }
  return null;
}

public String getDialogFolderUrl(String label) {
  Frame frame = new Frame();
  FileDialog fileDialog = new FileDialog(frame, label, FileDialog.LOAD);
  fileDialog.setVisible(true);
  return fileDialog.getDirectory();
}

public String[] getDialogAllFilesUrl(String label) {
  Frame frame = new Frame();
  FileDialog fileDialog = new FileDialog(frame, label, FileDialog.LOAD);
  fileDialog.setVisible(true);
  return getAllFilesFrom(fileDialog.getDirectory());
}

public String[] getAllFilesFrom(String folderUrl) {
  File folder = new File(folderUrl);
  File[] filesPath = folder.listFiles();
  String[] result = new String[filesPath.length];
  for (int i=0;i<filesPath.length;i++) {
    result[i]=filesPath[i].toString();
  }
  return result;
}

public void renameFile(String urlA, String urlB) {
  File file = new File(sketchPath(urlA));
  File file2 = new File(sketchPath(urlB));  
  boolean success = file.renameTo(file2);
  if (!success) {
    println(urlA + " was not renamed to " + urlB);
  }
}

public void copyDirectory(String urlA, String urlB) throws IOException {
  File srcDir = new File(sketchPath(urlA));
  File dstDir = new File(sketchPath(urlB));  
  try {
    copyDirectoryRec(srcDir, dstDir);
  } 
  catch (IOException e) {
    e.printStackTrace();
  }
}

public void copyDirectoryRec(File srcDir, File dstDir) throws IOException {
  // Copies all files under srcDir to dstDir.
  // If dstDir does not exist, it will be created.
  if (srcDir.isDirectory()) {
    if (!dstDir.exists()) {
      dstDir.mkdir();
    }
    String[] children = srcDir.list();
    for (int i=0; i<children.length; i++) {
      copyDirectoryRec(new File(srcDir, children[i]), new File(dstDir, children[i]));
    }
  } 
  else {
    // This method is implemented in Copying a File
    copyFile(srcDir, dstDir);
  }
}

public void copyFile(File src, File dst) throws IOException {
  // Copies src file to dst file.
  // If the dst file does not exist, it is created
  InputStream in = new FileInputStream(src);
  OutputStream out = new FileOutputStream(dst);

  // Transfer bytes from in to out
  byte[] buf = new byte[1024];
  int len;
  while ( (len = in.read (buf)) > 0) {
    out.write(buf, 0, len);
  }
  in.close();
  out.close();
}

  static public void main(String[] passedArgs) {
    String[] appletArgs = new String[] { "kernelConvolver" };
    if (passedArgs != null) {
      PApplet.main(concat(appletArgs, passedArgs));
    } else {
      PApplet.main(appletArgs);
    }
  }
}
