Pegel Spektrum zeichnen
Um ein Pegel Spektrum darzustellen, kann man aus der AudioSource den AudioBuffer mix auslesen. Die Methode toArray() des AudioBuffers mix gibt ein Float Array mit den einzelnen Pegeln im Buffer zurück. Diese Werte kann man dann verwenden, um ein Spektrum zu zeichnen. Ich habe für die Darstellung dann der Einfachheit halber Rechtecke gewählt.
Achtung: Es handelt sich hier um ein Spektrum der Pegel über die Zeit, nicht um ein Frequenzspektrum!
Beispiel: Spektrum zeichnen
// Library importieren
import ddf.minim.*;
// Objekte erstellen
Minim minim;
AudioPlayer input;
int x, y;
// Anzahl der Peaks
int grid=128;
// Abstand zwischen den Peaks
int spacing=1;
// Ausschlagmaximum für Peaks festlegen
float yScale = 2;
void setup() {
size(1024, 400);
smooth();
noStroke();
// Konstruktor des Minim Objekts aufrufen
minim = new Minim(this);
// Livestream vom FM4 laden, Größe des default sample buffer's ist 1024
input = minim.loadFile("http://mp3stream1.apasf.apa.at:8000");
// Wiedergabe starten
input.play();
}
void draw() {
// für etwas Bewegunsunschärfe
fill(50, 10);
rect(0, 0, width, height);
// Auslesen und speichern des Spektrums
float[] buffer = input.mix.toArray();
// Breite der Rechtecke berechnen
for (int i=1; i <= buffer.length; i+=buffer.length/grid) {
float x = map(i, 0, buffer.length, 0, width);
float y = map(buffer[i-1]*yScale, -1, 1, 0, height) ;
fill (102, 145, 250,100);
// Rechteck zeichnen
rect(x+spacing, height, width/grid-2*spacing, -y);
}
}
void stop()
{
// Player in schließen
input.close();
// Minim Object stoppen
minim.stop();
super.stop();
}
Frequenzen darstellen
Der Begriff Spekturm bezieht sich in der Regel auf ein Frequenzspektrum. Dieses kann mit Hilfe der Klasse FFT und der forward() Methode aus dem AudioBuffer errechnet werden. Dafür werden die Pegel im Buffer einer Fourier-Transformation unterzogen. Als Ergebnis erhält man keine einzelnen Frequenzen, sondern Frequenzbänder.
Umgekehrt kann man auch aus einem Frequenzspektrum ein Zeit-Pegel Spektrum ausgeben. Die Methode dafür heißt inverse();
Der auswertbare Frequenzbereich kann außerdem die halbe Sample-Frequenz nicht übersteigen. Die default Sample-Frequenz bei .mp3 und auf CD ist 44100 Hz, was eine maximale Frequenz von 22050 Hz für die Auwertung ergibt.
Einfaches Frequenzspektrum zeichnen
Um die FFT Klasse nutzen zu können, müssen wir zusätzlich zum letzten Beispiel die minim.analysis – Bibliothek importieren.
import ddf.minim.analysis.*;
Der folgende Code stellt ein Abwandlung des obigen Beispiels dar. Er zeichnet die Frequenzspektren der beiden Kanäle (left und right).
Beispiel: FFT Frequenzspektrum linear
// Library importieren
import ddf.minim.*;
import ddf.minim.analysis.*;
// Objekte erstellen
Minim minim;
AudioPlayer input;
FFT fftR, fftL;
int x, y;
// Anzahl der Peaks
int grid=32;
// Abstand zwischen den Peaks
int spacing=1;
// Ausschlagmaximum für Peaks festlegen
float yScale = 1;
void setup() {
size(1024, 400);
smooth();
noStroke();
// Konstruktor des Minim Objekts aufrufen
minim = new Minim(this);
// Livestream vom FM4 laden, Größe des default sample buffer's ist 1024
input = minim.loadFile("http://mp3stream1.apasf.apa.at:8000");
// Wiedergabe starten
input.play();
input.printControls();
// FFT-Instanz für die Spektrumsanalyse der beiden Kanäle
fftR = new FFT (input.bufferSize (), input.sampleRate ());
fftL = new FFT (input.bufferSize (), input.sampleRate ());
}
void draw() {
// für etwas Bewegunsunschärfe
fill(50, 10);
rect(0, 0, width, height);
// forwar FFT Analyse durchführen
fftR.forward(input.right);
fftL.forward(input.left);
// rechter Kanal
fill(255);
text("right Channel", 10, height/2+20);
// Breite der Rechtecke berechnen
for (int i=1; i <= fftR.specSize(); i+=fftR.specSize()/grid) {
float x = map(i, 0, fftR.specSize(), 0, width);
float y = map(fftR.getBand(i)*yScale, 0, 100, 0, height/2) ;
fill (102, 145, 250, 100);
// Rechteck zeichnen
rect(x+spacing, height, width/grid-2*spacing, -y);
}
// linker Kanal
fill(255);
translate(0, -height/2);
text("left Channel", 10, height/2+20);
// Breite der Rechtecke berechnen
for (int i=1; i <= fftL.specSize(); i+=fftL.specSize()/grid) {
float x = map(i, 0, fftL.specSize(), 0, width);
float y = map(fftL.getBand(i)*yScale, 0, 100, 0, height/2) ;
fill (102, 145, 250, 100);
// Rechteck zeichnen
rect(x+spacing, height, width/grid-2*spacing, -y);
}
}
void stop()
{
// Player in schließen
input.close();
// Minim Object stoppen
minim.stop();
super.stop();
}
Wie man an dem Spektrum unschwer erkennen kann, entspricht die Darstellung nicht unserer Wahrnehmung. Eine logarithmische Darstellung der Frequenzen ist hier angebracht. Mit FFT Klasse kann man eine solche Umwandlung mit der Methode logAverages() vornehmen.
Beispiel: FFT Frequenzspektrum logarithmisch
![]()
// Library importieren import ddf.minim.*; import ddf.minim.analysis.*; // Objekte erstellen Minim minim; AudioPlayer input; FFT fftR, fftL; int x, y; // Anzahl der Peaks int grid=20; // Abstand zwischen den Peaks int spacing=5; // Ausschlagmaximum für Peaks festlegen float yScale = 1; void setup() { size(1024, 400); smooth(); noStroke(); // Konstruktor des Minim Objekts aufrufen minim = new Minim(this); // Livestream vom FM4 laden, Größe des default sample buffer's ist 1024 input = minim.loadFile("http://mp3stream1.apasf.apa.at:8000";,2048); // Wiedergabe starten input.play(); input.printControls(); // FFT-Instanz für die Spektrumsanalyse der beiden Kanäle fftR = new FFT (input.bufferSize (), input.sampleRate ()); fftL = new FFT (input.bufferSize (), input.sampleRate ()); fftR.logAverages(11, 16); fftL.logAverages(11, 16); } void draw() { // für etwas Bewegunsunschärfe fill(50, 10); rect(0, 0, width, height); // forwar FFT Analyse durchführen fftR.forward(input.right); fftL.forward(input.left); // rechter Kanal fill(255); text("right Channel", 10, height/2+20); // Breite der Rechtecke berechnen for (int i=0; i < fftR.avgSize(); i+=fftR.avgSize()/grid) { //println(fftR.avgSize()); float x = map(i, 0, fftR.avgSize(), 0, width); //println(fftR.getAvg(i)); float y = map(fftR.getAvg(i)*yScale, 0, 100, 0, height/5) ; fill (102, 145, 250, 100); // Rechteck zeichnen rect(x+spacing, height, width/grid-2*spacing, -y); } // linker Kanal fill(255); translate(0, -height/2); text("left Channel", 10, height/2+20); // Breite der Rechtecke berechnen for (int i=0; i < fftL.avgSize(); i+=fftL.avgSize()/grid) { float x = map(i, 0, fftL.avgSize(), 0, width); float y = map(fftL.getAvg(i)*yScale, 0, 100, 0, height/5) ; fill (102, 145, 250, 100); // Rechteck zeichnen rect(x+spacing, height, width/grid-2*spacing, -y); } } void stop() { // Player in schließen input.close(); // Minim Object stoppen minim.stop(); super.stop(); }Eine weitere Möglichkeit der FFT Klasse ist die Veränderung der Pegel einzelner Frequenzbereiche mit scaleBand() und setBand(). Siehe dazu die JavaDoc.
Beat Detection
Auch hier gibt es wieder 2 Möglichkeiten. Einerseits kann man nur mit den Levels (Amplituden) arbeiten - SOUND_ENERGY. Oder aber man nutzt FREQUENCY_ENERGY und greift die Levels in einzelnen Frequenzbändern ab.
Beispiel: BeatDetect mit SoundEnergy
// Library importieren import ddf.minim.*; import ddf.minim.analysis.*; // Objekte erstellen Minim minim; AudioPlayer input; BeatDetect beat; float eRadius; void setup() { size(512, 512); smooth(); noStroke(); // Konstruktor des Minim Objekts aufrufen minim = new Minim(this); // Livestream vom FM4 laden, Größe des default sample buffer's ist 1024 input = minim.loadFile("http://mp3stream1.apasf.apa.at:8000"); // Wiedergabe starten input.play(); input.printControls(); // Erstellt die BeatDetect Instanz beat = new BeatDetect(); ellipseMode(CENTER_RADIUS); } void draw() { // für etwas Bewegunsunschärfe fill(50, 50); rect(0, 0, width, height); // Initiiert die BeatDetection beat.detect(input.mix); fill (102, 145, 250, 100); // Trigger der BeatDetection if ( beat.isOnset() ) eRadius = 3; if ( eRadius < 0.1 ) eRadius = 0.1; // Zeichnet die Kreise for (float i=1;i<10;i+=0.3) { fill(102, 145, 250, 10/i*i); ellipse(width/2, height/2, eRadius*i*i, eRadius*i*i); } eRadius *= 0.95; } void stop() { // Player in schließen input.close(); // Minim Object stoppen minim.stop(); super.stop(); }Beispiel: BeatDetect mit FrequencyEnergy
Hier kann man mit den Methoden isKick(), isSnare() und isHat() Peaks in den Frequenzbändern abrufen, die den jeweiligen Schlagzeugbausteinen entsprechen. Das funktioniert allerdings nicht bei allen Musiktypen gleich gut. Bei Problemen kann man noch auf die Funktion isRange(int low, int high, int threshold) zurückgreifen.
// Library importieren import ddf.minim.*; import ddf.minim.analysis.*; // Objekte erstellen Minim minim; AudioPlayer input; BeatDetect beat; BeatListener bl; float radKick, radSnare, radHat; void setup() { size(1024, 512); smooth(); noStroke(); // Konstruktor des Minim Objekts aufrufen minim = new Minim(this); // Livestream vom FM4 laden, Größe des default sample buffer's ist 1024 input = minim.loadFile("http://mp3stream1.apasf.apa.at:8000"); // Wiedergabe starten input.play(); input.printControls(); // Erstellt die BeatDetect Instanz // Im Frequency Mode müssen BufferSize und SampleRate übergeben werden. beat = new BeatDetect(input.bufferSize(), input.sampleRate()); //Setzt die Zeit, in der der Algorithmus keine weiteren Beats meldet beat.setSensitivity(200); ellipseMode(CENTER_RADIUS); textAlign(CENTER, CENTER); } void draw() { // für etwas Bewegunsunschärfe fill(50, 100); rect(0, 0, width, height); // Initiiert die BeatDetection beat.detect(input.mix); fill (102, 145, 250, 100); // Trigger der BeatDetection if ( beat.isKick() ) radKick = 2.5; if ( beat.isSnare() ) radSnare = 2.5; if ( beat.isHat() ) radHat = 2.5; if ( radKick < 0.1 ) radKick = 0.1; if ( radSnare < 0.1 ) radSnare = 0.1; if ( radHat < 0.1 ) radHat = 0.1; // Zeichnet die Kreise for (float i=1;i<10;i+=0.3) { fill(102, 145, 250, 10/i*i); ellipse(width/4, height/2, radKick*i*i, radKick*i*i); } // Zeichnet die Kreise for (float i=1;i<10;i+=0.3) { fill(255, 0, 50, 10/i*i); ellipse(width/2, height/2, radSnare*i*i, radSnare*i*i); } // Zeichnet die Kreise for (float i=1;i<10;i+=0.3) { fill(255, 200, 0, 10/i*i); ellipse(width*3/4, height/2, radHat*i*i, radHat*i*i); } //Zeichnet den Text fill(255); text("Kick", width/4, height/2); text("Snare", width/2, height/2); text("Hat", width*3/4, height/2); radKick *= 0.9; radSnare *= 0.9; radHat *= 0.9; } void stop() { // Player in schließen input.close(); // Minim Object stoppen minim.stop(); super.stop(); }




