/**
 *  Auto Correlation multiples each sample in a buffer by all
 *  of the other samples. This emphasizes the fundamental
 *  frequency. Auto Correlation is useful for pitch detection,
 *  as well as for visualization
 *
 *  This example is a Correlogram which is a plot
 *  of the autocorrelations.
 *
 *  Example by Jason Sigal and Golan Levin.
 */

var source, fft;
var bNormalize = true;
var centerClip = false;

function setup() {
  createCanvas(windowWidth, windowHeight);
  noFill();

  source = new p5.AudioIn();
  source.start();

  fft = new p5.FFT();
  fft.setInput(source);
}

function draw() {
  background(200);

  // array of values from -1 to 1
  var timeDomain = fft.waveform(2048, 'float32');
  var corrBuff = autoCorrelate(timeDomain);

  beginShape();
  for (var i = 0; i < corrBuff.length; i++) {
    var w = map(i, 0, corrBuff.length, 0, width);
    var h = map(corrBuff[i], -1, 1, height, 0);
    splineVertex(w, h);
  }
  endShape();
}

function autoCorrelate(buffer) {
  var newBuffer = [];
  var nSamples = buffer.length;

  var autocorrelation = [];
  var index;

  // center clip removes any samples under 0.1
  if (centerClip) {
    var cutoff = 0.1;
    for (var i = 0; i < buffer.length; i++) {
      var val = buffer[i];
      buffer[i] = Math.abs(val) > cutoff ? val : 0;
    }
  }

  for (var lag = 0; lag < nSamples; lag++) {
    var sum = 0;
    for (index = 0; index < nSamples; index++) {
      var indexLagged = index + lag;
      if (indexLagged < nSamples) {
        var sound1 = buffer[index];
        var sound2 = buffer[indexLagged];
        var product = sound1 * sound2;
        sum += product;
      }
    }

    // average to a value between -1 and 1
    newBuffer[lag] = sum / nSamples;
  }

  if (bNormalize) {
    var biggestVal = 0;
    for (index = 0; index < nSamples; index++) {
      if (abs(newBuffer[index]) > biggestVal) {
        biggestVal = abs(newBuffer[index]);
      }
    }
    for (index = 0; index < nSamples; index++) {
      newBuffer[index] /= biggestVal;
    }
  }

  return newBuffer;
}
