dravaib_arduino-processing-equaliser/processing/EQarduino_processing/EQarduino_processing.pde
import ddf.minim.*;
import ddf.minim.analysis.*;
import processing.serial.*;

Serial myPort;
Minim minim;
AudioInput in;
FFT fft;
PeakThread peakThread;
import javax.swing.*;


PFont font;
boolean has_serial = false;
float[] peaks;
int[] abars;
int customGain;
int bp = 250;
int gp = 0;
int rp = 0;
int iBrightness = 30;
String[] abarsString;

HScrollbar redscroll;
HScrollbar greenscroll;
HScrollbar bluescroll;
HScrollbar brightness;


final int[] freqs = {4, 6, 12, 25, 40, 80, 250, 400};
final int GAIN  = 3;
final int BAR_WIDTH = 8;
final int BAR_HEIGHT = 5;
final int DELAY = 20;
final int SAMPLING_FREQUENCY = 44100;
final int SAMPLING_DATA_RATE = 4096;
final int SERIAL_BAUD_RATE = 250000;
final int FRAME_RATE = 360;
final int WINDOW_WIDTH = 1024;
final int WINDOW_HEIGHT = 768;
final int RECT_WIDTH = 50;
final int RECT_HEIGHT = 50;
final int PEAK_HEIGHT_RATIO = 1;
final int PEAK_FALL_STEP = RECT_HEIGHT;
final boolean WAVE_ON = false;
final boolean DEBUG = false;


void setup()
{
  if (DEBUG) {
    printArray(Serial.list());
  }

  if (Serial.list().length == 0) {
    println("No COM port found");
  } else {
    myPort = new Serial(this, Serial.list()[0], SERIAL_BAUD_RATE);
    has_serial = true;
  }

  font = createFont("Arial", 16, true); 
  textFont(font);       
  fill(255);

  minim = new Minim(this);
  in = minim.getLineIn(Minim.MONO, SAMPLING_DATA_RATE, SAMPLING_FREQUENCY);
  fft = new FFT(in.left.size(), SAMPLING_FREQUENCY);
  peaks = new float[BAR_WIDTH];
  abars = new int[BAR_WIDTH];
  abarsString = new String[BAR_WIDTH];

  frameRate(FRAME_RATE);
  size(1024, 600, P2D);

  bluescroll = new HScrollbar(width/2-255, 100, 255, 16, 16);
  greenscroll = new HScrollbar(width/2-255, 150, 255, 16, 16);
  redscroll = new HScrollbar(width/2-255, 200, 255, 16, 16);
  brightness = new HScrollbar(width/2-255, 250, 255, 16, 16);


  bluescroll.setPos(bp+275);

  customGain = 0;

  for (int i=0; i<peaks.length; i++) {
    peaks[i] = 0;
  }

  peakThread = new PeakThread();
  peakThread.start();
}

void draw()
{
  background(0);
  stroke(255);
  strokeWeight(1);


  bluescroll.update();
  bluescroll.display(0, 0, 255);
  greenscroll.update();
  greenscroll.display(0, 255, 0);
  redscroll.update();
  redscroll.display(255, 0, 0);


  text("Brightness", width/2-215, 235);
  brightness.update();
  brightness.display(20, 20, 20);


  if (brightness.locked) {
    iBrightness = (int) brightness.getPos()-275;
    iBrightness = iBrightness > 200 ? 200 : iBrightness;
    if (has_serial) {
      myPort.write("l" + iBrightness + "\n");
    }
  }

  if (bluescroll.locked) {
    bp = (int) bluescroll.getPos() - 275;
    if (has_serial) {
      myPort.write("b" + bp + "\n");
    }
  }

  if (greenscroll.locked) {
    gp = (int) greenscroll.getPos() - 275;
    if (has_serial) {
      myPort.write("g" + gp + "\n");
    }
  }

  if (redscroll.locked) {
    rp = (int) redscroll.getPos() - 275;
    if (has_serial) {
      myPort.write("r" + rp + "\n");
    }
  }

  fill(rp, gp, bp);
  rect(width/2+100, 100, 100, 100);


  fft.forward(in.left);

  int peakHeight = RECT_HEIGHT / PEAK_HEIGHT_RATIO;
  int barNumber = 0;

  for (int n : freqs) {

    float band = fft.getBand(n) * (GAIN + customGain);      
    int barOffsetX = barNumber * RECT_WIDTH;
    int currentBars = ((int) band) / RECT_HEIGHT;
    currentBars = currentBars > BAR_HEIGHT ? BAR_HEIGHT : currentBars;

    if (abars[barNumber] < currentBars) {
      currentBars = abars[barNumber]--;
      abars[barNumber] = currentBars+1;
    } else if (abars[barNumber] > currentBars) {
      currentBars = abars[barNumber]++;
      abars[barNumber] = currentBars-1;
    }

    abarsString[barNumber] = str(abars[barNumber]);

    for (int i=0; i<(currentBars); i++) {
      fill(rp, gp, bp);
      rect(barOffsetX, height - (i * RECT_HEIGHT), RECT_WIDTH, RECT_HEIGHT);
    }

    if (peaks[barNumber] < band) {
      peaks[barNumber] = currentBars * RECT_HEIGHT;
    }

    fill(255, 0, 0);
    rect(barOffsetX, height - peaks[barNumber], RECT_WIDTH, peakHeight);

    fill(255);
    textAlign(CENTER);
    text("Gain: " + customGain, 45, 30); 
    if (has_serial) {
      text("Arduino: " + Serial.list()[0], 50, 50);
    } else {
      text("Arduino: Not connected", 100, 50);
    }


    barNumber++;
  }

  if (WAVE_ON) {
    wave();
  }

  String peakString = "";

  for (int p=peaks.length-1; p>=0; p--) {
    peakString += (int)peaks[p]/RECT_HEIGHT;
  }

  String send = "i" + join(reverse(abarsString), "") + peakString  + "\n";

  if (DEBUG) println(send + "|" + abarsString.length);

  if (has_serial) {
    myPort.write(send);

    if (DEBUG) {
      println(myPort.read());
    }
  }

  delay(DELAY);
}


public class PeakThread extends Thread
{
  public void start()
  {
    super.start();
  }
  public void run()
  {
    while (true) {
      float max = 0;

      for (int i=0; i<BAR_WIDTH; i++) {
        if (abars[i] < peaks[i]) {
          peaks[i] -= PEAK_FALL_STEP;
          max = max < peaks[i] ? peaks[i] : max;
        }
      }

      max /= RECT_HEIGHT;
      max = 150 * max;
      max = max < DELAY ? DELAY*2 : max;
      delay((int) max);
    }
  }
}

class HScrollbar {
  int swidth, sheight;    // width and height of bar
  float xpos, ypos;       // x and y position of bar
  float spos, newspos;    // x position of slider
  float sposMin, sposMax; // max and min values of slider
  int loose;              // how loose/heavy
  boolean over;           // is the mouse over the slider?
  boolean locked;
  float ratio;

  HScrollbar (float xp, float yp, int sw, int sh, int l) {
    swidth = sw;
    sheight = sh;
    int widthtoheight = sw - sh;
    ratio = (float)sw / (float)widthtoheight;
    xpos = xp;
    ypos = yp-sheight/2;
    spos = xpos + swidth/2 - sheight/2;
    newspos = spos;
    sposMin = xpos;
    sposMax = xpos + swidth - sheight;
    loose = l;
  }

  void update() {
    if (overEvent()) {
      over = true;
    } else {
      over = false;
    }
    if (mousePressed && over) {
      locked = true;
    }
    if (!mousePressed) {
      locked = false;
    }
    if (locked) {
      newspos = constrain(mouseX-sheight/2, sposMin, sposMax);
    }
    if (abs(newspos - spos) > 1) {
      spos = spos + (newspos-spos)/loose;
    }
  }

  float constrain(float val, float minv, float maxv) {
    return min(max(val, minv), maxv);
  }

  boolean overEvent() {
    if (mouseX > xpos && mouseX < xpos+swidth &&
      mouseY > ypos && mouseY < ypos+sheight) {
      return true;
    } else {
      return false;
    }
  }

  void display(int red, int green, int blue) {
    fill(100);
    rect(xpos, ypos, swidth, sheight);
    /*if (over || locked) {
     //fill(0);
     } else {*/
    fill(red, green, blue);
    //}
    rect(spos, ypos, sheight, sheight);
  }

  void setPos(float p) {
    newspos = constrain(p, sposMin, sposMax);
  }

  float getPos() {
    // Convert spos to be values between
    // 0 and the total width of the scrollbar
    return spos * ratio;
  }
}

void keyPressed() {
  switch(keyCode) {
  case 139:
    customGain++;
    break;
  case 140:
    customGain--;
    break;
  case 68:
    if (has_serial) myPort.write("d\n");
    break;
  case 80:
    if (has_serial) myPort.write("p\n");
    break;
  case 86:
    if (has_serial) myPort.write("v\n");
    break;
  case 66:
    if (has_serial) myPort.write("b\n");
    break;
  case 67:
    if (has_serial) myPort.write("c\n");
    break;
  case 77: 
    {
      this.frame.setExtendedState(JFrame.ICONIFIED);
        println("minimize...");

      break;
    }
  case 88: 
    {
      if (has_serial) myPort.write("x\n");
      break;
    }
  }
  println("pressed: " + keyCode);

  println("gain: " + customGain);
}

void wave() {
  // draw the waveforms
  int a = 100;
  int b = a*2;
  strokeWeight(3);
  for (int i = 0; i < in.bufferSize() - 1; i++)
  {
    line(i, a + in.left.get(i)*b, i+1, a + in.left.get(i+1)*b);
  }
}

void stop()
{
  in.close();
  minim.stop();
  super.stop();
}