Current File : /home/jeshor13/11bsouth.com/HonkBoard0.6/sketch.js
// Jesse Horwitz Nov 5 2015

// how do I make using the admin interface clear --- what is the user flow??? 

// enable people to figure out what it is -- QR codes???

// Project the honk sign !!!!

// output data in a meaningful way 

// the way sounds effect our hearing 


// Questions: Draw spectrograph faster? , Save and recall JSON, Tips for sound isolation, Any other UI, data or sound recognition tips? sound Filters?

var honkSample1 = [73];
var honkSample2 = [0]
var honkSoundLevels = [honkSample1, honkSample2 /*, honkSample3, honkSample4, honkSample5*/ ]
var honkCount = 0
var honkCount0 = 0
var headlineText = "Your Honks"
var midlineText = "Today's Conditions:"
var bottomlineText = "Total Honks This Week:"
var modeSelector;
var mode = 'Sign';
var micCheckbox;
var micMode = true;
var honkSoundsCheckbox;
var honkSoundsMode = false;
var fft;
var mic;
var p_spectrum = []
var p_spectrumMax = [0]
var p_spectrumAvg = []
var spectrum = [];
var backgroundHonkTimer = 0
var trailingAvgTimer = 0
var spectrographDrawTimer = 1000
var leastSq = 0
var mousePressTimer = 0;
var spectrograph = []
var honkStoreTimer = 0
var analysies = 0
var fftSpectrumLength = 350
var adjSpectrum = [0]
  //var adjHonkSoundLevels = []
var leastSqHonk = []
var leastSqAvg = 0
var leastSqZero = 0
var honkJson = {}
var honkData = []
var analysiesPerTime = 0
var filterTop
var filterBottom
var peakDetect;
var pauseMode = false;
var globalArray = []
var spectsTime = 0
var soundRecCount = 0
var displayHonkCount = 0
var displayHonkCount0 = 0
var displayHonkCountTimer = 0
var honkCount1 = 0
var whileHonks = 0
var notHonkCeiling = 0
var honkFloor = 0
var nonHonkFeather = 0
var honkFeather = 0
var minHonkPeaks = 0
var minNonHonkValleys = 0
var notHonkCeilingInput
var honkFloorInput
var nonHonkFeatherInput
var honkFeatherInput
var minHonkPeaksInput
var minNonHonkValleysInput
var notHonkCeilingLable
var honkFloorLable
var nonHonkFeatherLable
var honkFeatherLable
var minHonkPeaksLable
var minNonHonkValleysLable
var theSign
var panicMode = false
var panicNotches = 0
var panicTimer = 0
var streetSoundsCheckBox


function preload() {
  externalMedia() // see media.js for external files
}

function setup() {
  theSign = createCanvas(windowWidth, windowHeight * 0.90) // create canvas using full display width and 90% of 
    //
    // micCheckbox = createCheckbox('Mic?', true);
    // micCheckbox.changed(micCheckedEvent);
    //
  honkSoundsCheckbox = createCheckbox('Honk Sounds?', false);
  honkSoundsCheckbox.changed(honkSoundsCheckedEvent);

  //
  button = createButton('Save Honk Data [Broken]');
  button.mousePressed(saveOut);

  //
  button2 = createButton('Pause');
  button2.mousePressed(pause);

  //

  selector = createSelect();
  selector.option('Sign');
  selector.option('Data');
  selector.option('Settings');
  selector.changed(selectorEvent);
  //
  //
  //filterTop = new p5.LowPass()
  //filterTop.setType("highpass")
  //   //filterBottom = new p5.HighShelf
  //filterTop.freq(500)
  //   //filterBottom.freq(350)
  // mic = new p5.AudioIn();
  // //mic.connect(filterTop)
  // mic.start();
  fft = new p5.FFT();
  fft.setInput();

  carHorns = [carHornsLong, carHornsShort, carHornsShort2,
    carHornsLong2, carHornsLong3, carHornOne, streetSound1/*, streetSound2*/
  ];
  carHorns[6].loop()

  // 
  loadJSON('Honks.json', dataLoader)

  //
  // domInputs = [notHonkCeilingInput, honkFloorInput, nonHonkFeatherInput, honkFeatherInput, minHonkPeaksInput, minNonHonkValleysInput]


  notHonkCeilingInput = createInput();
  notHonkCeilingInput.size(25)
  notHonkCeilingInput.position(windowWidth * 0.23, windowHeight * 0.33);
  notHonkCeilingInput.attribute("value", 12.5)
  notHonkCeilingInput.input(notHonkCeilingInputChanged)
  notHonkCeilingLable = createP('"Low" amplitude ceiling -  This value helps determine which frequencies are unusually loud')
  notHonkCeilingLable.position((windowWidth * 0.23) + 35, (windowHeight * 0.33) - 15);
  notHonkCeilingLable.style("color", "#ffffff")
  honkFloorInput = createInput();
  honkFloorInput.size(25)
  honkFloorInput.position(windowWidth * 0.23, (windowHeight * 0.33) + 45);
  honkFloorInput.attribute("value", 35)
  honkFloorInput.input(honkFloorInputChanged)
  honkFloorLable = createP('"High" amplitude floor -  This value helps determine which frequencies are very loud')
  honkFloorLable.position((windowWidth * 0.23) + 35, (windowHeight * 0.33) + 30);
  honkFloorLable.style("color", "#ffffff")
  nonHonkFeatherInput = createInput();
  nonHonkFeatherInput.size(25)
  nonHonkFeatherInput.position(windowWidth * 0.23, (windowHeight * 0.33) + 90);
  nonHonkFeatherInput.attribute("value", 12.5)
  nonHonkFeatherInput.input(nonHonkFeatherInputChanged)
  nonHonkFeatherLable = createP('Low-sound foward tolerance - Helps to identify continous low  or average sounds')
  nonHonkFeatherLable.position((windowWidth * 0.23) + 35, (windowHeight * 0.33) + 75);
  nonHonkFeatherLable.style("color", "#ffffff")
  honkFeatherInput = createInput();
  honkFeatherInput.size(25)
  honkFeatherInput.position(windowWidth * 0.23, (windowHeight * 0.33) + 135);
  honkFeatherInput.attribute("value", 1.5)
  honkFeatherInput.input(honkFeatherInputChanged)
  honkFeatherLable = createP('High-sound foward tolerance - Helps to identify continuous loud sounds')
  honkFeatherLable.position((windowWidth * 0.23) + 35, (windowHeight * 0.33) + 120);
  honkFeatherLable.style("color", "#ffffff")
  minHonkPeaksInput = createInput();
  minHonkPeaksInput.size(25)
  minHonkPeaksInput.position(windowWidth * 0.23, (windowHeight * 0.33) + 180);
  minHonkPeaksInput.attribute("value", 3)
  minHonkPeaksInput.input(minHonkPeaksInputChanged)
  minHonkPeaksLable = createP('Minimum peaks per honk - The number of continuous loud sounds lasting longer than 1/8th of a second')
  minHonkPeaksLable.position((windowWidth * 0.23) + 35, (windowHeight * 0.33) + 165);
  minHonkPeaksLable.style("color", "#ffffff")
  minNonHonkValleysInput = createInput();
  minNonHonkValleysInput.size(25)
  minNonHonkValleysInput.position(windowWidth * 0.23, (windowHeight * 0.33) + 225);
  minNonHonkValleysInput.attribute("value", int(fftSpectrumLength / 3))
  minNonHonkValleysInput.input(minNonHonkValleysInputChanged)
  minNonHonkValleysLable = createP('Minimum valleys per honk - The number of continuous low or average sounds lasting longer than 1/8th of a second')
  minNonHonkValleysLable.position((windowWidth * 0.23) + 35, (windowHeight * 0.33) + 210);
  minNonHonkValleysLable.style("color", "#ffffff")

  notHonkCeilingInput.hide()
  honkFloorInput.hide()
  nonHonkFeatherInput.hide()
  honkFeatherInput.hide()
  minHonkPeaksInput.hide()
  minNonHonkValleysInput.hide()
  notHonkCeilingLable.hide()
  honkFloorLable.hide()
  nonHonkFeatherLable.hide()
  honkFeatherLable.hide()
  minHonkPeaksLable.hide()
  minNonHonkValleysLable.hide()



  notHonkCeiling = 12.5
  honkFloor = 35
  nonHonkFeather = 12.5
  honkFeather = 1.5
  minHonkPeaks = 3
  minNonHonkValleys = int(fftSpectrumLength / 3)


}



function draw() {


  p_soundStorage()
  trailingAverage()
  honkDisplayNumber()
  soundRecCount++
  if (millis() > 2000) {
    spectsTime = int(analysiesPerTime / 8)
    soundRecognition2()
  }
  if (honkSoundsMode == true) {
    playHonkSound()
  }
  if (mode == 'Sign') {
    basicSign()
  }
  if (mode == 'Data') {
    consoleData()
    drawSpectrograph()
  }
  if (mode == 'Settings') {
    consoleData()
    consoleSettings()
  }
  //
  if (honkCount0 != honkCount) {
    honkData[honkData.length++] = {
      "seshID": honkCount,
      "honk": true,
      //"fft": spectrum,
      "time": [year(), month(), day(), hour(), minute(), second()]
    }
  }
  //
  honkCount0 = honkCount
  displayHonkCount0 = displayHonkCount
}

// function micCheckedEvent() {
//   if (this.checked()) {
//     micMode = true;
//     print("true");
//   } else {
//     micMode = false;
//     print("false");
//   }
// }

function honkSoundsCheckedEvent() {
  if (this.checked()) {
    honkSoundsMode = true;
  } else {
    honkSoundsMode = false
  }
}

function mousePressed() {
  if (millis() - mousePressTimer > 1000 && mouseX <= width * 0.99 && mouseY <= height * 0.20) {
    carHornOne.setVolume(0.3);
    carHornOne.play();
    mousePressTimer = millis()
  }
}

function selectorEvent() {
  mode = selector.value()
  if (mode == 'Sign') {
    background(0)
  }
  if (mode == 'Data') {
    background(230)
  }
  if (mode == 'Settings') {
    background(1)
  }
  if (mode != 'Settings') {
    notHonkCeilingInput.hide()
    honkFloorInput.hide()
    nonHonkFeatherInput.hide()
    honkFeatherInput.hide()
    minHonkPeaksInput.hide()
    minNonHonkValleysInput.hide()
    notHonkCeilingLable.hide()
    honkFloorLable.hide()
    nonHonkFeatherLable.hide()
    honkFeatherLable.hide()
    minHonkPeaksLable.hide()
    minNonHonkValleysLable.hide()
  }
}


function playHonkSound() {
  if (millis() - backgroundHonkTimer > 10000) {
    var i = int(random(0, 4))
    carHorns[i].setVolume(0.3);
    carHorns[i].play();
    backgroundHonkTimer = millis()
  }
}

function trailingAverage() { // consider adjusting this so that you only update the average whith new numbers
  if (millis() - trailingAvgTimer >= 500) {
    for (var i = 0; i < p_spectrum[0].length; i++) {
      var frequency = i;
      var sumAmplitude = 0;
      for (var j = 0; j < p_spectrum.length; j++) {
        var currentSpectrum = p_spectrum[j];
        var amplitude = currentSpectrum[frequency];
        sumAmplitude += amplitude;
      }
      var averageAmplitude = sumAmplitude / p_spectrum.length;
      p_spectrumAvg[frequency] = averageAmplitude;
    }
    trailingAvgTimer = millis()
  }
}

function drawSpectrograph() {

  if (millis() - spectrographDrawTimer > 5000) {
    var xMap = []
    var yMap = []
    var fillFreq = []
    var p_i = 0
    var p_j = 0
      // each rectangle is 1/4rd of a second and ?? Hz
    for (var i = 0; i < 160; i++) {
      for (var j = 0; j < 160; j++) {
        xMap.push(int(map(i, 0, 160, width * 0.22, width * 0.99)))
        yMap.push(int(map(-j, -160, 0, 0, height * 0.99)))
        var ii = ceil(map(i, 0, 160, 0, p_spectrum.length))
        var jj = ceil(map(j, 0, 160, 0, p_spectrum[i].length))
        var kk = p_spectrum[ii]
        fillFreq.push(kk[jj])
      }
    }

    colorMode(HSB)
    noStroke()
    var cc = ceil((((width * 0.99) - (width * 0.22)) / (sqrt(xMap.length))))
    var gg = ceil((height * 0.98) / (sqrt(xMap.length)))
    for (var k = 0; k < (xMap.length); k++) {
      fill(fillFreq[k], 225, 255)
      rect(xMap[k], (yMap[k]), cc, gg)
    }
    colorMode(RGB)
    spectrographDrawTimer = millis()
  }
}

function p_soundStorage() {
  spectrum = fft.analyze();
  for (var zz = 0; zz < (((1024) - (fftSpectrumLength))); zz++) {
    spectrum.pop()
  }
  for (var i = 0; i < honkSoundLevels.length; i++) {
    for (var iii = 0; iii < (((honkSoundLevels[i].length) - (fftSpectrumLength))); iii++) {
      honkSoundLevels[i].pop()

    }
  }

  p_spectrum.push(spectrum)
  analysies++
  if (millis() - honkStoreTimer > 1000) {
    analysiesPerTime = analysies
    analysies = 0
    honkStoreTimer = millis()
  }

  while (p_spectrum.length >= 30 * analysiesPerTime && p_spectrum.length >= 100) {
    p_spectrum.shift()
  }
}

// function soundRecognition1() {
//   leastSqHonk = []
//   leastSqHonk.length = honkSoundLevels.length
//   leastSqAvg = 0
//   leastSqZero = 0
//   for (ii = 0; ii < honkSoundLevels.length; ii++) {
//     var kk = honkSoundLevels[ii]
//     for (var jj = 0; jj < spectrum.length; jj++) {
//       leastSqHonk[ii] = int(leastSqHonk[ii] + ((kk[jj] - spectrum[jj]) * (kk[jj] - spectrum[jj])))
//       leastSqAvg = int(leastSqAvg + (p_spectrumAvg[jj] - spectrum[jj]) * (p_spectrumAvg[jj] - spectrum[jj]))
//       leastSqZero = int(leastSqZero + (0 - spectrum[jj]) * (0 - spectrum[jj]))
//     }

//   }
  // var honkMatch = 0
  // for (pp = 0; pp < honkSoundLevels.length; pp++) {
  //   if ((leastSqHonk[pp] / (honkSoundLevels[pp].length)) <= (leastSqAvg / p_spectrumAvg.length) && ((leastSqZero / p_spectrumAvg.length) >= leastSqAvg / p_spectrumAvg.length)) {
  //     honkMatch++
  //   }
  // }
  // if (honkMatch >= 1) {
  //   honkCount++
  // }
// }



function soundRecognition2() {
  // First determine if a single spectrum has 
  var possibleHonks = []
  var noiseLen = 1
  var nonHonks = []
  var avgLen = 1
  spectsTime = int(analysiesPerTime / 8)

  for (j = p_spectrum.length - spectsTime; j < p_spectrum.length; j++) {
    for (i = 0; i < fftSpectrumLength; i++) {


      if (p_spectrum[j][i] < int(p_spectrumAvg[i] + notHonkCeiling /*+ (0.0005 * i)*/ )) {
        avgLen = 1
        for (v = avgLen; v < spectsTime; v++) {
          if (p_spectrum.length > j + v) {
            if (p_spectrum[j + v][i] > (p_spectrum[j][i] - nonHonkFeather)) {
              if (p_spectrum[j + v][i] < (p_spectrum[j][i] + nonHonkFeather)) {
                avgLen++
              }
            }
          }
        }
        if (avgLen > spectsTime - 2) {
          nonHonks.push(avgLen)
        }
      }
      if (p_spectrum[j][i] > int(p_spectrumAvg[i] + honkFloor)) {
        noiseLen = 1
        for (k = noiseLen; k < spectsTime; k++) {
          if (p_spectrum.length > j + k) {
            if (p_spectrum[j + k][i] > (p_spectrum[j][i] - honkFeather)) {
              if (p_spectrum[j + k][i] < (p_spectrum[j][i] + honkFeather)) {
                noiseLen++
              }
            }
          }
        }
        if (noiseLen > spectsTime - 2) {
          possibleHonks.push(noiseLen)
        }
      }
    }
  }
  var honkMatch = 0
  if ((possibleHonks.length > minHonkPeaks) && (nonHonks.length > minNonHonkValleys)) {
    honkMatch++
  }
  if (honkMatch >= 1) {
    honkCount++
    whileHonks++
  }
}

function dataLoader(jsonHonk) {
  honkData = [jsonHonk]
}

function saveOut() { //NOT YET WORKING
  if (honkCount0 == honkCount) {
    print(honkData)
    saveJSON(honkData, 'Honks.json');
    //{ "seshID": 0, "honk": false, "fft": [0], "time": [ 0, 0, 0, 0, 0,0 ]}
  }
}

function pause() {
  pauseMode = !pauseMode
  if (pauseMode == true) {
    noLoop()
  } else {
    loop()
  }
}

// domInputs = [notHonkCeilingInput, honkFloorInput, nonHonkFeatherInput, honkFeatherInput, minHonkPeaksInput, minNonHonkValleysInput]

function notHonkCeilingInputChanged() {
  if (notHonkCeilingInput.value() > 0 && notHonkCeilingInput.value() < 255) {
    notHonkCeiling = int(notHonkCeilingInput.value())
    print(notHonkCeiling)
  }
}

function honkFloorInputChanged() {
  if (honkFloorInput.value() > 0 && honkFloorInput.value() < 255) {
    honkFloor = int(honkFloorInput.value())
    print(honkFloor)
  }
}

function nonHonkFeatherInputChanged() {
  if (nonHonkFeatherInput.value() > 0 && nonHonkFeatherInput.value() < 255) {
    nonHonkFeather = int(nonHonkFeatherInput.value())
    print(nonHonkFeather)
  }
}

function honkFeatherInputChanged() {
  if (honkFeatherInput.value() > 0 && honkFeatherInput.value() < 255) {
    honkFeather = int(honkFeatherInput.value())
    print(honkFeather)
  }
}

function minHonkPeaksInputChanged() {
  if (minHonkPeaksInput.value() > 0 && minHonkPeaksInput.value() < fftSpectrumLength) {
    minHonkPeaks = int(minHonkPeaksInput.value())
    print(minHonkPeaks)
  }
}

function minNonHonkValleysInputChanged() {
  if (minNonHonkValleysInput.value() > 0 && minNonHonkValleysInput.value() < fftSpectrumLength) {
    minNonHonkValleys = int(minNonHonkValleysInput.value())
    print(minNonHonkValleys)
  }
}