import processing.core.*; 
import processing.xml.*; 

import ddf.minim.*; 
import ddf.minim.analysis.*; 
import javax.swing.JFileChooser; 

import java.applet.*; 
import java.awt.*; 
import java.awt.image.*; 
import java.awt.event.*; 
import java.io.*; 
import java.net.*; 
import java.text.*; 
import java.util.*; 
import java.util.zip.*; 
import java.util.regex.*; 

public class Aufgabe_4 extends PApplet {





// initialize
PFont font;
Minim minim;
AudioPlayer player;
FFT fft;
float maxSpec = 0;

public void setup() {
  size (500, 300);
  smooth();
  stroke (100);
  
  // create audiokit
  minim = new Minim (this);
  // load audio file
  player = minim.loadFile("song.mp3");
  player.loop();
  
  // define fft instance for spectrum analysis
  fft = new FFT(player.bufferSize(), player.sampleRate());
  
  // load font and set as default
  font = loadFont("HelveticaNeue-Bold-40.vlw");
  textFont(font);
  textSize(16);
}

public void draw() {
  background(45);
 
  // fetch current play position
  float playPos = player.position ();
  float playLen = player.length ();
  float xpos = (playPos / playLen) * width;
  
  // draw progress bar
  fill(alpha(color(0,126,255,102)));
  stroke(alpha(color(0,126,255,102)));
  rect (0, 0, xpos, 20);

  // draw waveform
  stroke(36,109,107);
  saturation(10);
  for(int i = 0; i < player.left.size()-1; i++)
  {
    line(i, 50 + player.left.get(i)*50, i+1, 500 + player.left.get(i+1)*50);
    line(i, 150 + player.right.get(i)*50, i+1, 150 + player.right.get(i+1)*50);
  }

  // draw equalizer
  float g = 0;    // Gr\u00fcnwert der F\u00fcllfarbe
  float h = 0;    // H\u00f6he von Rechteck und Linie
  float specStep; // Breite einer horiz. Linie
  float specScale = (float) width / (fft.specSize () - 1);
 
  // create frequency groups (16 array) / possible steps 2-4-8-16-32-64-128
  float[] group = getGroup (16);
 
  // draw detailed frequency spectrum
  noStroke ();
  for (int i = 0; i < fft.specSize (); i++) {
    g = map (fft.getBand (i), 0, maxSpec, 50, 255);
    h = map (fft.getBand (i), 0, maxSpec, 2, height);
    fill (0, g, 0);
    rect (i * specScale, height - h, specScale, h);
  }
 
  // draw groups (lines)
  stroke (255, 255, 0, 200);
  specStep = width / group.length;
  for (int i=0; i < group.length; i++) {
    h = height - map (group[i], 0, maxSpec, 0, height);
    line (i * specStep, h, (i+1) * specStep, h);
  }
  
  // text
  if (player.isPlaying()) {
    textSize(16);
    fill(255);
    text ("Now playing:  " + player.getMetaData().author() + " - " + player.getMetaData().title(), 4,4, width, 200);
  }
}

public void keyPressed() {
  if (key == ' ') {
    if (player.isPlaying()) {
      player.pause();
      textSize(20);
      text ("Playback paused", 0/2,0, width, 200);
    } else {
      player.play();
    }  
  }
}

public void mousePressed() {
  // get click coordinates
  float pos = ((float) mouseX / width) * player.length();
  // jump to position
  player.cue((int) pos);
}

/** 
 * Funktion fasst das vorliegende FFT-Spektrum
 * in eine durch den Parameter 'theGroupNum' 
 * festgelegte Anzahl von gleichgro\u00dfen Bereichen
 * zusammen \u2013 und gibt deren Mittelwert zur\u00fcck.
 */
public float[] getGroup (int theGroupNum) {
  fft.forward (player.mix);
 
  // Leeres Array f\u00fcr die Gruppen erstellen
  float[] group  = new float[theGroupNum];
  // Das FFT-Spekturm hat eine Stelle mehr 
  // als beim Input definiert. (256->257).
  // Diese wird ignoriert.
  int specLimit  = fft.specSize () - 1;
  // Anzahl der Frequenzb\u00e4nder pro Gruppe
  int groupSize = specLimit / theGroupNum;
 
  // Alle Gruppen mit einem Startwert f\u00fcllen
  for (int i=0; i < group.length; i++) {
    group[i] = 0;
  }
 
  // F\u00fcr jedes FFT-Frequenz-Band
  for (int i=0; i < specLimit; i++) {
    // Maximum?
    if (fft.getBand (i) > maxSpec) {
      maxSpec = fft.getBand (i);
    }
    // Jedes Band einer Gruppe zuweisen
    int index = (int) Math.floor (i / groupSize);
    group[index] += fft.getBand (i);
  }
 
  // Der Wert jeder Gruppe durch die Anzahl
  // der enthaltenen B\u00e4nder Teilen - >Mittelwert
  for (int i=0; i < group.length; i++) {
    group[i] /= groupSize;
  }
  // Gruppe zur\u00fcck geben.
  return group;
}

public void stop() {
  player.close();
  minim.stop();
  super.stop();
}


  static public void main(String args[]) {
    PApplet.main(new String[] { "--bgcolor=#FFFFFF", "Aufgabe_4" });
  }
}
