3.6 Klanganalyse

Voices and Piano (Peter Ablinger, seit 1998) (Website)
"Actually the piano part is the temporal and spectral scan of the respective voice, something like a coarse gridded photograph. Actually the piano part is the analysis of the voice. Music analyses reality."

Magnetosphere (flight404/Robert Hodgin, 2007)

Yarn Audio Netlabelday 2016


1. Die minim-Library

Die Sound-Library von Processing bietet zwar einige Möglichkeiten zur Klangerzeugung und -wiedergabe, doch sind ihre Möglichkeiten zur Klanganalyse reduziert. Hier empfiehlt es sich wiederum auf die minim-Library zurückzugreifen.

2. Amplitude auslesen

Die Library importieren:


import ddf.minim.*;
import ddf.minim.analysis.*;

Soundfile laden:


minim = new Minim(this);
song = minim.loadFile("dot.mp3", 2048);

Beispiel 3-11


Minim  minim;
AudioPlayer player;

float xPos = 0;
float yPos1 = 0;
float yPos2 = 0;
float lastX = 0;
float lastY = 0;

void setup() {
  size(800, 600);
  background(255);
  fill(0);  

  minim = new Minim(this);
  player = minim.loadFile("dot.mp3");
  player.loop();
}      

void draw() {
  float ampLeft = abs(player.left.get(0));
  float ampRight = abs(player.right.get(0));
  float ampSum = ampLeft + ampRight;
  println(ampSum);
  yPos1 = height/2-(ampSum*height);
  yPos2 = height/2+(ampSum*height);
  ellipse(xPos, yPos1, 2, 2);
  ellipse(xPos, yPos2, 2, 2);
  line(xPos, yPos1, xPos, yPos2);
  if (xPos < width){
    xPos+=4;
  }else{
    fill(255, 230);
    stroke(255);
    rect(0,0,width, height);
    fill(0);
    stroke(0);
    xPos = 0;
  }
}

3. Fast Fourier Transformation

Zeit-basierte Darstellung (oben) und Frequenz-basierte Darstellung (unten) desselben Signals, wobei die untere Darstellung aus der oberen durch Fouriertransformation gewonnen werden kann. (Quelle: Wikipedia Commons)

Die minim-Library stellt ein FFT-Objekt bereit:


Minim  minim;                        
AudioPlayer player;
FFT fft;

minim = new Minim(this);
player = minim.loadFile("dot.mp3");      
player.loop();

fft = new FFT(player.bufferSize(), player.sampleRate());

Mit der Funktion logAverages teilt man dem FFT-Objekt mit was die unterste Frequenz sein soll und wieviele (Analyse-)Bänder pro Oktave verwendet werden soll.


fft.logAverages(55, 6);      // Tiefster Ton: 55Hz (A1), 6 (Analyse-)Bänder pro Oktave
fft.forward(player.mix);      // Analysiere den Stereo-Mix des zuvor erstellten AudioPlayers "player"

Nun lassen sich die einzelnen Frequenzbänder mit fft.getBand(); auslesen.

Beispiel 3-12


import ddf.minim.*;                  // import minim library
import ddf.minim.analysis.*;

Minim  minim;                        
AudioPlayer player;
FFT fft;

int tonstufen = 24;
int cutHigh = tonstufen*6;            // cut higher part of spectrum (6 Oktaves)
float x = 0;
int shape = 1;

void setup(){
  size(1280,720, P3D);
  pixelDensity(2);
  background(0);
  rectMode(CENTER);
  minim = new Minim(this);
  player = minim.loadFile("dot.mp3");      
  player.loop();
  fft = new FFT(player.bufferSize(), player.sampleRate());
  fft.logAverages(55, tonstufen);      // Tiefster Ton: 55Hz (A1), 6 (Analyse-)Bänder pro Oktave
  fft.forward(player.mix);
}

void draw(){
   fill(255,6);
   stroke(255,40);
    fft.logAverages(55, tonstufen);      
    fft.forward(player.mix);
    for (int i = 0; i < fft.specSize(); i++){
       float value = fft.getBand(i);
       float radius = map(value, 0, 10, 0, 6);
       switch(shape){
         case 1:
           ellipse(x, height-(i*40), value, value);
           break;
         case 2:
           rect(x, height-(i*40), value, value);
           break;
         case 3:
           stroke(255,150);
           line(x, height-(i*40), x+value, height-(i*40)+value);
           break;
       }
    }
    if (x

Beispiel 3-13


import ddf.minim.*;                  // import minim library
import ddf.minim.analysis.*;

Minim  minim;                        //
AudioPlayer player;
FFT fft;

float lastX=0;
float lastY=0;
float radius = 200;
int tonstufen = 6;
int cutHigh = tonstufen*6;                    // cut higher part of spectrum (6 Oktaves)
float stepsize; 
float rotation = 0;
float rSpeed = 0;

void setup(){
  size(1280,720, P3D);
  pixelDensity(2);
  background(0);

   minim = new Minim(this);
   player = minim.loadFile("dot.mp3");      
   player.loop();
   fft = new FFT(player.bufferSize(), player.sampleRate());
   fft.logAverages(55, tonstufen);      // Tiefster Ton: 55Hz (A1), 6 (Analyse-)Bänder pro Oktave
   fft.forward(player.mix);
   stepsize = 360/(fft.avgSize()-cutHigh);
}

void draw(){ 
  fill(0,10);
  rect(0,0,width, height);
  rotation += rSpeed; 
  fft.logAverages(55, tonstufen);      // Tiefster Ton: 55Hz (A1), 6 (Analyse-)Bänder pro Oktave
  fft.forward(player.mix);
  float totalAmp = 0;

  int i =0;
  for (int angle = 0; angle < 360; angle += stepsize ){ 
    float radAng = radians(angle+rotation);
    float value = fft.getBand(i);
    totalAmp += value;
    float xc = width/2 + cos(radAng)*(radius+(value*5));
    float yc = height/2 + sin(radAng)*(radius+(value*5));
    stroke (255, 100);
    fill(255, 150);
    if (i == 0){
      line(xc, yc, width/2, height/2);
    }
    ellipse(xc,yc, 6, 6);
    line(lastX, lastY, xc, yc);
    lastX=xc;
    lastY=yc;
    i++;
  }
  if (totalAmp > 100){
    rSpeed = randomGaussian() *2;
    //rotation += randomGaussian()*30;
  }
}