float[][] freqs = { { 130.81, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    { 261.63, 246.94, 233.08, 220.00, 207.65, 196.00, 185.00, 174.61, 164.81, 155.56, 145.83, 138.59 },
                    { 392.00, 369.99, 349.23, 329.63, 311.13, 293.66, 277.18, 0, 0, 0, 0, 0 },
                    { 523.25, 493.88, 466.16, 440.00, 415.30, 0, 0, 0, 0, 0, 0, 0 },
                    { 649.23, 622.23, 587.33, 554.37, 0, 0, 0, 0, 0, 0, 0, 0 },
                    { 783.99, 739.99, 698.46, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                    { 932.33, 880.00, 860.61, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                    { 1046.50, 987.77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } };

int len = 512;
float global_freq, phase, phaseAdder, vol;

Overtone[] ot = new Overtone[8];
float ox = 22.5, oy = 77.5, w = 13.83, h = 200;

boolean global_over = false;
boolean start = false;

float emouseX, vs = 0;

BImage labels, cover;

void setup()
{
  size(600,300);
  Sonia.start(this, 22048);
  LiveOutput.start(len, len*2);
  LiveOutput.setSleep(5);
  LiveOutput.startStream();

  ot[0] = new Overtone(ox, oy, w*4, h, freqs[0], color(255,128,128), 1);
  ot[1] = new Overtone(ox+w*4, oy, w, h, freqs[1], color(255,128,0), 12);
  ot[2] = new Overtone(ox+w*16, oy, w, h, freqs[2], color(255,255,128), 7);
  ot[3] = new Overtone(ox+w*23, oy, w, h, freqs[3], color(0,255,128), 5);
  ot[4] = new Overtone(ox+w*28, oy, w, h, freqs[4], color(128,255,255), 4);
  ot[5] = new Overtone(ox+w*32, oy, w, h, freqs[5], color(0,128,255), 3);
  ot[6] = new Overtone(ox+w*35, oy, w, h, freqs[6], color(128,128,255), 3);
  ot[7] = new Overtone(ox+w*38, oy, w, h, freqs[7], color(255,128,255), 2);
  
  labels = loadImage("labels.gif");
  cover = loadImage("cover.jpg");
}

void loop()
{
  background(0);
  draw_bg(color(128,192,255), color(255,255,255));
  
  
  if (!start) {
    image(cover, 0, 0);
  } else {
    display();
    play_with_it();
  }
}

void display()
{
  for (int i = 0; i < ot.length; i++)
    ot[i].draw();
    
  stroke(0);
  for (int i=0; i < len-1; i++) {
    float dx = lerp(0,555,1/512);
    line(44 + i, LiveOutput.data[i]*30 + oy/2, 44 + (i+1), LiveOutput.data[(i+1)]*30 + oy/2);
  }
  
    image(labels, ox+w*4+w/2, oy+2);
}

void play_with_it()
{
  global_over = (mouseX >= ox && mouseY >= oy && mouseX <= ox+(w*40) && mouseY <= oy+h) ? true : false;
  
  set_vol();
 
  set_emouseX();
}

void draw_bg(color a, color b)
{
 beginShape(POLYGON);
 fill(a);
 vertex(0,0);
 vertex(width, 0);
 fill(b);
 vertex(width, height);
 vertex(0, height);
 endShape();
}

void set_emouseX()
{
  float M = 0.8;
  float K = 0.2;
  float D = 0.70;
  float f,as;
  f = -K * (emouseX - mouseX);
  as = constrain(f / M, -17, 17);
  vs = D * (vs + as);
  emouseX = emouseX + vs;
  if (global_over)
    rect(emouseX - 5, mouseY -5, 10, 10);
}

void liveOutputEvent(){
  if(mousePressed && global_over){
    phaseAdder = global_freq/11025f;
    for (int i = 0; i < len; i++) {
      phase += phaseAdder;
      if (phase > 1f) phase -= 2f;
      LiveOutput.data[i] = vol*sin(phase*PI);
    }
  }else {
    for (int i=0; i < len; i++) {
      LiveOutput.data[i] = 0;
    }
  }
}

void set_vol()
{
  vol = 0.8 - lerp(0.1, 0.8, (float)mouseY/height);
}

class Overtone
{
  float x,y,w,h;
  float[] freqs;
  color c;
  int num;
  float noteW, noteH;
  float a;
  int currentKey = -1;
  int valveDiff = 0;

  Overtone(float $x, float $y, float $w, float $h, float[] $freq, color $c, int $num)
  {
    x = $x; y = $y; w = $w*$num; h = $h;
    freqs = $freq;
    c = $c;
    num = $num;
    noteW = $w;
    noteH = h;
  }

  void draw()
  {
    if (over()) {
      work_valves();
      set_freq(freqs[valveDiff]);
      a = 0;
    } else {
      a = 64;
    }

    fill(c);
    noStroke();
    rect(x,y,w,h);
    for (int i = 0; i < num; i++) {
      if (over() && currentKey == i) {
        fill(255,215);
      } else if (over() && currentKey == -1 && i == num-1) {
        fill(255,235);
      } else {
        fill(lerp(128,255,(float)i/num) , lerp(0,192,(float)i/num));
      }
      rect(x+(i*noteW), y, noteW, noteH);
    }
    label();
    fill(0,a);
    rect(x,y,w,h);
  }

  void work_valves()
  {
    int[] keys = { 48,57,56,55,54,53,52,51,50,49,96 };
    if (keyPressed) {
      for (int i = keys.length-1; i >= 0; i--) {
        if (keys[i] == key) {
          currentKey = num-2-i;
          valveDiff = i+1;
        }
      }
    } else {
      currentKey = -1;
      valveDiff = 0;
    }
  }
  
  void label()
  {
    /**String s;
    for (int i = 0; i < 11; i++) {  
      s = (i == 0) ? "`" : "";
      s = (i == 1) ? "1" : "";
      s = (i == 2) ? "2" : "";
      s = (i == 3) ? "3" : "";
      s = (i == 4) ? "4" : "";
      s = (i == 5) ? "5" : "";
      s = (i == 6) ? "6" : "";
      s = (i == 7) ? "7" : "";
      s = (i == 8) ? "8" : "";
      s = (i == 9) ? "9" : "";
      s = (i == 10) ? "0" : "";
      fill(0);
      text(s, x+i*noteW - noteW/2, y+10);
    }**/
  }

  boolean over()
  {
    return (emouseX >= x && emouseX <= x+w && mouseY >= y && mouseY <= y+h) ? true : false;
  }
}

void set_freq(float freq)
{
  global_freq = freq;
}

float lerp(float mn, float mx, float d)
{
  return (mx - mn)*d + mn;
}

float powlerp(float mn, float mx, float d)
{
  return mn + pow((mx - mn)*-d,2)/mx;
}

float cubic_lerp(float t, float b, float c, float d) {
  return -c * (t/=d)*(t-2) + b;
}

public void stop() {
  Sonia.stop();
  super.stop();
}

void mousePressed()
{
  if (!start) start = true;
}
Project 4: Context
Extend an idea you've explored previously in your life, but adapt it to the context of an interactive system which requires the viewer to engage with the material.