P5 und P5.sound - 3D Waterfall Display (einmalig)



Zunächst werden im <head> der Seite die beiden Scripte für P5 und P5.sound eingebunden:

<script src="header/p5.js"></script>
<script src="header/p5.sound.js"></script>

Dann wird im <body> der Seite ein Container mit einer eindeutigen id mithilfe von DIV-Tags angelegt, in dem alles angezeigt werden soll. Dies geschieht via

<DIV id="p5container"></DIV>

über Style-Eigenschaften kann man diesen noch weiter im Aussehen verändern, z.B.

<DIV id="p5container" style="width:800;border: 1px solid #333;box-shadow: 8px 8px 5px #444;padding: 8px 12px;background-color:ffffff"></DIV>

Das dazugehörende Script ist wie fast alle P5 Scripte aufgebaut:
Erst werden über die Funktion preload() größere Dateien vorausgeladen:

function preload(){
sound = loadSound('klang/fagott_toene.mp3');
}

Dann werden in der Funktion setup() die Grundkomponenten festgelegt:

function setup(){
var container = createCanvas(800,400); // Canvas erstellen
container.parent('p5container'); // an DIV-Container anhängen
container.mouseClicked(togglePlay); // auf Klick auf Canvas reagieren
fft = new p5.FFT(); // Fouriertransformation des Signals ermöglichen
sound.amp(0.5); // Amplitude des vorausgeladenen Klangs "sound" auf die Hälfte reduzieren
}

Außerhalb der setup()-Funktion und vor der darauffolgenden draw()-Funktion wird eine Variable als Startpunkt für den Offset auf der X- und Y-Achse definiert, d.h. von diesem Punkt ausgehend wird der Offset mit jeder FFT erneut immer weiter nach rechts und nach oben verschoben, bis alle Frames des Sonagramms gezeichnet werden, also:

var zaehler = 0;

Dazu wird ein Schalter definiert, um sicherzugehen, dass nur dann das Spektrum gezeichnet wird, wenn auch der Klang abgespielt wird:

var schalter=0;

Daraufhin wird in der Funktion draw() beschrieben, was im Canvas dargestellt werden soll:

function draw(){
cursor(HAND); // zeige den Cursor als Hand
var spectrum = fft.analyze(); // mache eine Spektralanalyse in der Länge des aktuellen
// Frames und schreibe sie ins Array spectrum
if (schalter==1){ // sobald der Klang abgespielt wird (s.u.), mache folgendes:
noFill(); // Flächen sollen nicht ausgefüllt werden (keine Füllfarbe)
stroke(188,48,48); // Strichfarbe auf ein dunkles rot setzen
strokeWeight(0.5); // Strichdicke auf 0.5 setzen
beginShape();
// das Zeichnen einer Form beginnen
for (var i = 0; i < spectrum.length; i++){ // hole in einer Schleife in der Länge
// des Arrays spectrum jeden einzelnen Wert i aus dem Array (= jeden Frequenzbereich)

var x = map(i, 0, spectrum.length, 0, width*4); // skaliere die aufsteigend
// gezählten Zahlen i (von 0 bis Ende des spectrum Arrays) so, dass sie von 0 bis zur vierfachen
// Weite des Canvas dargestellt werden (da in den höheren Frequenzanteilen so gut wie keine
// Amplituden sind) und weise sie der Variablen x zu (Frequenz auf der X-Achse).

var y = map(spectrum[i], 0, 255, height, 0); // skaliere jeden Wert
// aus dem Array spectrum, der zwischen 0 und 255 liegt, so, dass er zwischen der Höhe des Canvas
// und 0 dargestellt wird. Weise ihn dann dem Wert y zu (Amplituden der einzelnen Frequenzen auf
// der Y-Achse)

vertex(x+zaehler,y-zaehler); // weise x und y als Koordinaten eines Punkts zu, der einen
// Eckpunkt der dazustellenden Gesamtform (via beginshape(); s.o.) beschreibt. Durch die Addition
// bzw. Subtraktion mit den ansteigenden Zahlen aus dem Zähler wird der Beginn Punkts (und damit
// die ganze Hüllkurve) mit jedem Schritt etwas weiter nach rechts und nach oben verschoben.

}
endShape(); // Schließe die Gesamtform ab, in ihr ist dann ein Ausschnitt des Spektrums pro
// Frame dargestellt, der dann immer weiter nach rechts oben verschoben wird.

}
if (sound.isPlaying()) { // wenn der Klang "sound" gespielt wird
schalter=1; // setze die Variable schalter auf 1
zaehler=zaehler+1; // und zähle 1 zur Variable Zähler dazu
} else { // in allen anderen Fällen
schalter=0; // Setze die Variable schalter auf 0
zaehler=0; // Setze die Variable zaehler auf 0
}
}

Schließlich wird mit der Funktion togglePlay() beschrieben, was passieren soll, wenn auf den Canvas geklickt wird

function togglePlay() {
if (sound.isPlaying()) { // wenn der Klang "sound" gespielt wird
sound.pause(); // stoppe ihn
} else { // in allen anderen Fällen
sound.play(); // spiele ihn ab.
background(255, 255, 255, 10); // färbe den Hintergrund weiß
}
}

Insgesamt sieht das Script dann folgendermaßen aus:

<script src="header/p5.js"></script>
<script src="header/p5.sound.js"></script>

<script>
function preload(){
sound = loadSound('klang/fagott_toene.mp3');
}

function setup(){
var container = createCanvas(800,400);
container.parent('p5container');
container.mouseClicked(togglePlay);
fft = new p5.FFT();
sound.amp(0.5);
}

var schalter=0;
var zaehler=0;

function draw(){
cursor(HAND);
var spectrum = fft.analyze();
if (schalter==1){
noFill();
stroke(188,48,48);
strokeWeight(0.5);
beginShape();
for (var i = 0; i< spectrum.length; i++){
var x = map(i, 0, spectrum.length, 0, width*4);
var y = map(spectrum[i], 0, 255, height, 0);
vertex(x+zaehler,y-zaehler);
}
endShape();
}

if (sound.isPlaying()) {
schalter=1;
zaehler=zaehler+1;
} else {
schalter=0;
zaehler=0;
}
}

function togglePlay() {
if (sound.isPlaying()) {
sound.pause();
} else {
sound.play();
background(255, 255, 255);
}
}
</script>

<DIV id="p5container" style="width:800;border: 1px solid #333;box-shadow: 8px 8px 5px #444;padding: 8px 12px;background-color:ffffff"></DIV>