Interaktives Audio-Experiment: Sound-Visualizer mit p5.js
Interaktives Audio-Experiment: Sound-Visualizer mit p5.js
Inhalt des Tutorials
In diesem Tutorial lernst du, wie man mithilfe p5.js, durch Tasteneingabe verschiedene Töne abspielen und diese dann in einer visuellen Darstellung in Form einer Linie visualisieren kann. Zusätzlich dazu bewegen sich Partikel aus dem Kreis heraus. Die Geschwindigkeit der Partikel wird von den abgespielten Tönen beeinflusst.
Hierbei gibt es neun Töne, welche man mit den Tasten 1 bis 9 abspielen kann.
Folgende Punkte werden in diesem Tutorial behandelt:
Tastatureingabe in P5.js
Partikelbildung
Beeinflussung von Musikfrequenzen auf Objekte
Interaktivität
Hier ist einmal eine mögliche Ausgabe dargestellt:
01 - Lieder importieren
Bevor mit dem coden begonnen wird, sollten erstmal die jeweiligen Audiodateien (auf die der Visualizer reagieren soll) heruntergeladen werden. Diese sollen in die P5.js Datei importiert werden.
02 - Grundlagen
Zu Beginn werden drei globale Variabeln definiert. Song, fft und particles in Form eines Feldes.
Die Variabel „song“ wird verwendet, um die Audioclips zu laden.
Die Variabel „fft“ wird verwendet, um eine Frequenzanalyse der Audios durchzuführen und die visuelle Darstellung des Frequenzspektrums zu erzeugen.
In der Variabel „particles“, welche als Feld gespeichert wird, werden die erstellten Partikel gespeichert.
var song;
var fft;
var particles = [];
03 - setup()
In der Setup Funktion wird eine Zeichenfläche erstellt, die hier so groß wie das Fenster sein soll. Zudem wird ein FFT (Fast Fourier Transform) Objekt erstellt, um das Audio-Signal zu analysieren und in seine Frequenzanteile zu zerlegen. Der Winkelmodus wird auf Grad gestellt, um es einfacher zu machen, die Frequenzen in Grad zu berechnen und diese zu visualisieren.
function setup() {
createCanvas(windowWidth, windowHeight);
angleMode(DEGREES);
fft = new p5.FFT();
}
04 - draw()
In der draw()-Funktion
werden zuerst die grundliegenden Elemente festgelegt. Dier Hintergrund wird schwarz eingefärbt, um die weiße Linie zu sehen. Ebenso wird festgelegt, dass es keine Füllung gibt, damit nur die Linie sichtbar ist.
Mit strokeWeight()
kann die Linienstärke festgelegt und verändert werden.
function draw() {
background(0);
stroke(255);
noFill();
strokeWeight(3);
05 - Kreis / Wave erstellen
Zuerst wird eine Linie erstellt, welche die Musik später visualisieren soll. Diese wird zu einem Halbkreis umgeformt.
Um einen Halbkreis zu erstellen, wird eine for-Schleife verwendet, um die Linie umzuformen. Dabei wird die Kurvenform eines Halbkreises gezeichnet. Dieser Schritt passiert zweimal. Einer der erstellten Halbkreise wird mit negativen Zahlen erstellt, damit dieser gespiegelt wird und durch die zwei Halbkreise ein Kreis entsteht.
Um den Kreis in der Mitte zu platzieren, wird das Koordinatensystem mithilfe von translate()
in die Mitte verschoben.
Die Frequenzen der Musik werden durch fft.analyze
herausanalysiert.
fft.waveform
speichert diese analysierten Daten in einem Feld und returnt diese. In der if-Schleife wird dieses Feld ausgewertet und verformt somit den Kreis je nach Frequenzen der Audiodateien um.
Dies wird alles in der draw()-Funktion
erstellt.
//in die Mitte verschieben
translate(width / 2, height / 2);
//Audiodatei analysieren
fft.analyze();
amp = fft.getEnergy(20, 200);
//Kreis/Wellenform
var wave = fft.waveform();
for (var t = -1; t <= 1; t += 2) {
beginShape();
for (var i = 0; i <= 180; i += 0.5) {
var index = floor(map(i, 0, width, 0, wave.length - 1));
var r = map(wave[index], -1, 1, 150, 350);
var x = r * sin(i) * t;
var y = r * cos(i);
vertex(x, y);
}
endShape();
}
06 - Partikel
Die Partikel werden in der Klasse „Particle“ definiert. In dieser kann die Farbe, Größe und der Ausgangsort der Partikel festgelegt und verändert werden.
//Partikel
var p = new Particle();
particles.push(p);
for (var i = particles.length - 1; i >= 0; i--) {
if (!particles[i].edges()) {
particles[i].update(amp > 150);
particles[i].show();
} else {
particles.splice(i, 1);
}
}
}
class Particle {
constructor() {
this.pos = p5.Vector.random2D().mult(250);
this.vel = createVector(0, 0);
this.acc = this.pos.copy().mult(random(0.0001, 0.00001));
this.w = random(3, 5);
this.color = "magenta";
}
update(cond) {
this.vel.add(this.acc);
this.pos.add(this.vel);
if (cond) {
this.pos.add(this.vel);
this.pos.add(this.vel);
this.pos.add(this.vel);
}
}
Um die Partikel zu erstellen, werden Partikel Objekte der Klasse Particle benötigt.
Die Partikel werden mithilfe der Funktion particles.push(p)
in dem am Anfang erstelltem Array var particles = []
gespeichert.
Das Element particles[i].update(amp > 150);
sorgt dafür, dass die Partikel responsiv zur Amplitude der Musik sind. Genau genommen macht das amp. Den Wert kann man je nach Audio anpassen. In diesem Fall wird 150 gewählt. Je niedriger der Wert eingestellt wird, desto sensiebler reagieren die Partikel auf die Musik.
Mit this.w = random(3, 5);
wird die Größe der Partikel variiert und willkürlich gesetzt, um das Ganze organischer aussehen zu lassen.
Die update Methode updatet die Position der Partikel.
Mit this.color()
Kann die Farbe der Partikel bestimmt und umgeändert werden.
Die Partikel sollen eine Position haben, welche als ein Vektor definiert werden kann. Wenn ein Partikel entsteht, soll die Platzierung dieses zufällig an der Wellenbewegung des Kreises erfolgen.
Das kann mit der p5.Vector. random2D().mult(250)-Methode
erreicht werden. Der erstellte p5 Vektor hat eine Länge von 1. Dieser wird mit dem Radius des Kreises (250) multipliziert. Jetzt werden Partikel zufällig nur auf der Kreislinie erstellt.
Damit die Partikel nicht nur am Kreis bleiben, sondern sich nach außen wegbewegen muss die Velocity dieser mithilfe von this.vel
verändert werden.
edges() {
if (
this.pos.x < -width / 2 ||
this.pos.x > width / 2 ||
this.pos.y < -height / 2 ||
this.pos.y > height / 2
) {
return true;
} else {
return false;
}
}
Mit der Funktion edges()
werden die Partikel, die die Fläche verlassen haben aus dem Array entfernt.
Um die Partikel auf dem Canvas darstellen zu können, wird die Methode show()
verwendet.
In dieser wird die vorherig definierte Farbe den Partikeln zugewiesen. Außerdem wird mithilfe noStroke()
definiert, dass die Partikel keine Konturlinie besitzen sollen.
show() {
noStroke();
fill(this.color);
ellipse(this.pos.x, this.pos.y, this.w);
}
07 - Tastatureingabe
Um in P5.js die Tastatur, beziehungsweise einzelne Tasten als Eingabe für das Programm benutzen zu können, müssen sogenannte keycodes verwendet werden. Auf der Seite keycode.info
kann durch das drücken der jeweiligen Taste der jeweilige Keycode in Erfahrung gebracht werden. Zum Beispiel ist der Keycode für die Taste „1“ die Nummer 49.
In der Funktion keyPressed()
wird definiert welche Audiodatei beim drücken welcher Taste abgespielt wird. Um festzulegen welche Musik bei welcher Tasteneingabe gespielt wird, braucht man ineinander geschachtelte if-Schleifen.
Die erste if-Schleife, um zu definieren ob eine Taste gedrückt wurde und die zweite um eine Aktion festzulegen, je nach dem welche Taste gedrückt wurde. Um eine Taste für eine Aktion zu definieren, muss der jeweilige Keycode dieser Taste angegeben werden.
function keyPressed() {
if (keyIsPressed == true) {
if (keyCode == 49 || keyCode == 97) {
if (song1.isLooping()) {
song1.stop();
} else {
song1.play();
song1.loop();
}
}
Wenn die Taste „1“ gedrückt wird, wird der erste Sound abgespielt.
Mithilfe der .loop-Methode
, wird die Audiodatei endlos wiederholt, bis sie beim erneuten Drücken derselben Taste wieder beendet wird.
In diesem Fall haben wir 9 Audiodateien auf die Tasten 1 bis 9 verteilt, die mit genau dem gleichen Prinzip abgespielt werden.
Durch das drücken der Taste „0“ wird das Abspielen aller Audiodateien beendet.
if (keyCode == 48 || keyCode == 96) {
if (
song1.isLooping() ||
song2.isLooping() ||
song3.isLooping() ||
song4.isLooping() ||
song5.isLooping() ||
song6.isLooping() ||
song7.isLooping() ||
song8.isLooping() ||
song9.isLooping()
) {
song1.stop();
song2.stop();
song3.stop();
song4.stop();
song5.stop();
song6.stop();
song7.stop();
song8.stop();
song9.stop();
}
}
08 - Lieder laden
Um die Audiodateien selber abspielen zu können, müssen diese auch im Code importiert werden.
Funktionen werden bei P5.js in der aufgelisteten Reihenfolge bearbeitet, deshalb ist die oberste Funktion, die preload()-Funktion
, mit welcher die Audiodateien geladen werden. Dadurch, dass diese am Anfang steht wird sichergestellt, dass die Lieder korrekt geladen werden.
Um die Lieder tatsächlich in die Variabel laden zu können, kann die loadSound()-Funktion
benutzt werden. In dieser muss die Verlinkung der Datei festgehalten werden.
function preload() {
song1 = loadSound("Eguitar.mp3");
song2 = loadSound("tribe-drum.mp3");
song3 = loadSound("triangle.mp3");
song4 = loadSound("kick-drum.mp3");
song5 = loadSound("groove.mp3");
song6 = loadSound("bass.mp3");
song7 = loadSound("bass2.mp3");
song8 = loadSound("percussive.mp3");
song9 = loadSound("synth2.mp3");
}
Jetzt kann man durch das drücken der Tasten 1 bis 9 die verschiedenen Töne abspielen. Der Kreis in der Mitte visualisiert die Musik durch die Wellenform und die Partikel reagieren ab einer bestimmten Frequenz ebenfalls auf die Musik.
09 - Zusammenfassung
Mithilfe p5.js kann beim Drücken verschiedener Tasten eine Aktion ausgeführt werden. In diesem Beispiel wurde eine Audiodatei abgespielt, die mithilfe ihrer Frequenzen einen Audio Visualizer beeinflusst.
Durch die ausgewählten Töne können beispielsweise kleine Melodien kreiert werden.
Quellcode
Hier findest du den gesamten Quellcode, die Audiodateien und unsere Inspiration für das Tutorial. Viel Spaß beim ausprobieren!