P5
und P5.sound - Sonagramm
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 ide 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
background(255,255,255); // der Hintergrund
wird ganz zu Anfang auf weiss festgelegt, da
// er in der Funktion draw() pro Fram erneut überschrieben wird (anders
als sonst wird er diesmal
// nicht jedesmal erneut in draw() auf weiß gesetzt).
}
Außerhalb
der setup()-Funktion und
der darauffolgenden draw()-Funktion
wird eine Variable als Startpunkt für den Offset auf der X-Achse
definiert, d.h. von diesem Punkt ausgehend wird der Offset mit jeder FFT
erneut immer weiter nach rechts verschoben, bis alle Frames des Sonagramms
gezeichnet werden, also:
var xoffset = 0;
Daraufhin
wird in der Funktion draw()
beschrieben, was im Canvas dargestellt werden soll:
function draw(){
cursor(HAND); // zeige den Cursor als Hand
noStroke(); // keine Striche farblich ausfüllen
(keine Strichfarbe)
var bins = fft.analyze(); // mache eine
Spektralanalyse in der Länge des aktuellen
// Frames und schreibe sie ins Array bins.
for (var i = 0; i <
bins.length; i++){ // hole in einer Schleife
in der Länge
// des Arrays bin jeden einzelnen Wert i aus dem Array (= jeden Frequenzbereich)
var drawY = map(bins.length-i, 0, bins.length, 0, height*2); //
skaliere die
// Zahlen i (von 0 bis zur Länge des bins-Arrays) so, dass sie von
0 bis zur zweifachen Höhe des
// Canvas dargestellt werden (da in den höheren Frequenzanteilen
so gut wie keine Amplituden mehr
// sind) und weise sie der Variablen drawY zu (Frequenz auf der Y-Achse).
var rectHeight = height / bins.length; //
Errechne die Höhe des zu zeichnenden
// Rechtecks (pro bin-Wert) aus dem Quotienten zwischen der Höhe
des Canvas und der Anzahl der bins
// im Array (= der Länge des bins-Arrays).
var rectWidth = width/sound.duration()/getFrameRate(); //
Errechne die Weite
// des zu zeichnenden Rechtecks (pro bin-Wert) aus dem Quotienten von
Weite des Canvas geteilt
// durch Länge des Klangbeispiels geteilt durch Frame-Rate des Canvas.
fill(255-bins[i], 255-bins[i], 255-bins[i]); //
Ziehe den jeweiligen bins-Wert von
// den RGB-Werten für die Füllfarbe pro zu zeichnendes Rechteck
ab (= Färbung der einzelnen Punkte
// des Sonagramms)
rect(xoffset, drawY-height, rectWidth, rectHeight);
// zeichne pro bins-Wert ein
// Rechteck mit dem xoffset-Wert als X-Koordinate und dem von der Canvas-Höhe
abgezogene drawY-Wert
// als Y-Koordinate, sowie mit der vorher definierten Weite (rectWidth)
und Höhe (rectHeight).
// Jedes Rechteck stellt einen Punkt des Sonagramms dar.
}
if (sound.isPlaying()) { // sobald der
Klang abgespielt wird:
xoffset += width/sound.duration()/getFrameRate(); //
erhöhe den Offset um einen
// Faktor, der sich aus dem Quotienten von Weite des Canvas geteilt durch
Länge des Klangbeispiels
// geteilt durch Frame-Rate des Canvas ergibt.
}
}
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.
}
}
Von dieser
Grundstruktur ausgehend ist es nicht mehr schwer z.B. den Spectral Centroid
oder den jeweils stärksten Teilton im im Sonagramm zu markieren (wie
z.B. oben auf der Seite in der Anwendung).
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();
background(255,255,255);
}
var xoffset = 0;
function draw(){
cursor(HAND);
noStroke();
var bins = fft.analyze();
for (var i = 0; i < bins.length; i++) {
var drawY = map(bins.length-i, 0, bins.length, 0, height*2);
var rectHeight = height / bins.length;
var rectWidth = width/sound.duration()/getFrameRate();
fill(255-bins[i], 255-bins[i], 255-bins[i]);
rect(xoffset, drawY-height, rectWidth, rectHeight);
}
if (sound.isPlaying()) {
xoffset += width/sound.duration()/getFrameRate();
}
}
function togglePlay()
{
if (sound.isPlaying()) {
sound.pause();
} else {
sound.play();
}
}
</script>
<DIV id="p5container"
style="width:800;border: 1px solid #333;box-shadow: 8px 8px 5px
#444;padding: 8px 12px;background-color:ffffff"></DIV>
|