HTML5 und die Web-Audio-API, Teil 2: Wir erstellen ein visuelles Audiospektrum per Canvas

Kein Beitragsbild

Denis Potschien

Denis Potschien ist seit 2005 freiberuflich als Kommunikationsdesigner tätig, seit Anfang 2010...

Die neue Web-Audio-API mit ihren verschiedenen Möglichkeiten der Audiowiedergabe und -manipulation wurde hier bereits vorgestellt. Dabei haben wir einige der interessantesten Funktionen bereits vorgestellt. Ein recht komplexes Feld haben wir aber einem eigenem Artikel, nämlich diesem hier, vorbehalten. Denn, zusammen mit den Canvas-Zeichenfunktionen von JavaScript lässt sich damit auch ein visuelles Audiospektrum einer Wiedergabe realisieren.

audiocontext_spektrum

HTML-Elemente und „AudioContext“ bereitstellen

Zunächst einmal werden ein Audioelement sowie eine Leinwand für die JavaScript-Zeichenfunktion ausgezeichnet.

<audio src="musik.mp3" controls="controls"></audio>
<canvas width="300" height="250"></canvas>

Die Steuerung der Wiedergabe wird im Beispiel dem Audioelement überlassen, indem die Steuerleiste („controls“) eingeblendet wird. Per JavaScript wird die Wiedergabe der MP3-Datei abgegriffen, um die nötigen Informationen zur Darstellung eines Audiospektrums zu erhalten.

var musik = new AudioContext();
var quelle = musik.createMediaElementSource(document.getElementsByTagName("audio")[0]);
var analyse = musik.createAnalyser();

quelle.connect(analyse);
analyse.connect(musik.destination);

Nachdem im Beispiel das „AudioContext“-Objekt erstellt („musik“) und die Quelle („quelle“) definiert wurden, erzeugen wir mit „createAnalyser()“ eine sogenannte Frequenzanalyse, die das Zeitsignal der Wiedergabe analysiert und interpretiert. Die Werte dieser Analyse werden zur visuellen Darstellung des Audiospektrums genutzt.

Per „connect()“ verknüpfen wir die Quelle und die Analyse mit dem „AudioContext“-Objekt. Im nächsten Schritt legen wir fest, wie detailliert die Werte der Frequenzanalyse sein sollen. Dazu wird die Größe der „Fast Fourier Transformation“ (FFT) definiert. Per FFT schlüsseln wir das Zeitsignal der Wiedergabe in seine Frequenzen auf. Mit der Eigenschaft „fftSize“ wird angegeben, wie detailliert die Aufschlüsselung sein soll. Die Eigenschaft erwartet einen Wert zwischen 32 und 2048, wobei dieser immer eine Potenz von 2 sein muss.

analyse.fftSize = 64;
var frequenzdaten = new Uint8Array(analyse.frequencyBinCount);

Anschließend erstellen wir ein Array („frequenzdaten“), dem die Werte der Frequenzanalyse in ganzzahligen 8-Bit-Werten zugewiesen werden. Die Länge des Arrays wird per „frequencyBinCount“ abgerufen und festgelegt. Der Wert entspricht immer der Hälfte von „fftSize“ und somit der Anzahl der Balken, die für das Audiospektrum gezeichnet werden sollen. Da „fftSize“ im Beispiel auf 64 gesetzt wurde, stellt das Audiospektrum 32 Balken dar.

Optional gibt es noch die Eigenschaft „smoothingTimeConstant“. Sie gibt an, wie weich die Frequenzsprünge sein sollen. Die Eigenschaft erwartet einen Wert zwischen 0 und 1, wobei der Wert 0 für eine harte und somit sehr ruckelige Darstellung des Audiospektrums steht. Je mehr sich der Wert 1 nähert, je weicher und fließender ist die Bewegung im Audiospektrum. Der Standardwert liegt bei 0,8.

Kennst du unser E-Book-Bundle? Spare jetzt 6,99 €!

E-Book Bundle von Andreas Hecht
analyse.smoothingTimeConstant = 0.85;

Außerdem gibt es noch die optionalen Eigenschaften „minDecibels“ und „maxDecibels“, mit denen ein Mindest- und Höchstwert für die darzustellenden Dezibelwerte angegeben werden kann.

Audiospektrum programmieren

Im nächsten Schritt programmieren wir die eigentliche Visualisierung der Frequenzdaten als animiertes Audiospektrum. Dazu werden dem „<cancas>“-Element der 2D-Zeichenkontext zugewiesen und die Breite und Höhe der Leinwand ermittelt.

var leinwand = document.getElementsByTagName("canvas")[0].getContext("2d");
var leinwand_breite = document.getElementsByTagName("canvas")[0].offsetWidth;
var leinwand_hoehe = document.getElementsByTagName("canvas")[0].offsetHeight;

Die Leinwandgröße benötigen wir, um die Größe des Audiospektrums der Leinwand anzupassen. Über die Funktion „audiospektrum()“ zeichnen wir das Audiospektrum auf die Leinwand. Aufgerufen wird die Funktion per „requestAnimationFrame()“, sodass der Browser die Darstellung bei jeder Aktualisierung der Seitenanzeige neu zeichnet.

function audiospektrum() {

  analyse.getByteFrequencyData(frequenzdaten);
  leinwand.clearRect(0, 0, leinwand_breite, leinwand_hoehe);

  for (var i = 0; i < frequenzdaten.length; i++) {
    var balken_x = Math.round(leinwand_breite / frequenzdaten.length) * i;
    var balken_breite = Math.round(leinwand_breite / frequenzdaten.length) - 1;
    var balken_hoehe = leinwand_hoehe / 100 * Math.round(-frequenzdaten[i] / 255 * 100);
    var farbe_rot = frequenzdaten[i];
    var farbe_gruen = 255 - frequenzdaten[i];
    leinwand.fillStyle = "rgb(" + farbe_rot + ", " + farbe_gruen + ", 0)";
    leinwand.fillRect(balken_x, leinwand_hoehe, balken_breite, balken_hoehe);
  }

  window.requestAnimationFrame(audiospektrum);

}

window.requestAnimationFrame(audiospektrum);

Zunächst werden im Beispiel die jeweils aktuellen Frequenzdaten per „getByteFrequencyData()“ abgerufen. Per „clearRect()“ leeren wir die Leinwand bei jedem Funktionsaufruf.

Über eine „for“-Schleife berechnen wit für jeden Balken des Audiospektrums die X-Position des Balkens („balken_x“), die Breite („balken_breite“) sowie die Höhe („balken_hoehe“). Die Werte für die Höhe sind negativ, da die Balken vom unteren Leinwandrand nach oben wachsen. Die Y-Position entspricht immer der Höhe der Leinwand. Die jeweiligen Frequenzwerte, die per „frequenzdaten[i]“ verfügbar sind, können zwischen 0 und 255 liegen. Im Beispiel wird der Wert für die Höhe der Leinwand umgerechnet.

Die Balkenfarbe soll abhängig sein von der Balkengröße und zwischen Grün („farbe_gruen“) und Rot („farbe_rot“) variieren. Kleine Balken sind dabei grün und große Balken rot dargestellt. Da die Farbwerte ebenso wie die Frequenzwerte zwischen 0 und 255 liegen, lassen sich die Frequenzwerte einfach für die Farbdefinition einsetzen.

Per „fillStyle()“ definieren wir die Farbe des zu zeichnenden Balkens. Anschließend wird per „fillRect()“ der Balken mit den vorher berechneten Werten gezeichnet.

audiocontext_spektrum_beispiel
Audiospektrum in Aktion während der Wiedergabe

Sobald die Audiowiedergabe startet, wird das dazugehörige Audiospektrum auf die Leinwand des „<canvas>“-Elementes gezeichnet. Sobald die Wiedergabe endet, verschwinden die Balken wieder. Das Audiospektrum reagiert auch bei Veränderung durch den Lautstärkeregler in der Steuerleiste des Audioelements.

Alternative Darstellungsformen

Mit relativ wenig Aufwand lässt sich die Darstellungsform des Audiospektrums verändern. Da innerhalb der „for“-Schleife die Zeichenmethoden untergebracht sind, genügt es, dort ein paar Änderungen vorzunehmen für ein anderes Aussehen.

for (var i = 0; i < frequenzdaten.length; i++) { 
  var kreis_radius = leinwand_hoehe / 100 / 2 * (i / frequenzdaten.length * 100);
  var farbe_rot = frequenzdaten[i];
  var farbe_gruen = 255-frequenzdaten[i];
  var farbe_alpha = 1 * (frequenzdaten[i] / 255);
  leinwand.beginPath();
  leinwand.strokeStyle = "rgba(" + farbe_rot + ", " + farbe_gruen + ", 0, " + farbe_alpha + ")";
  leinwand.lineWidth = 5 * (frequenzdaten[i] / 255);
  leinwand.arc(leinwand_breite / 2, leinwand_hoehe / 2, kreis_radius, 0, 2 * Math.PI, false);
  leinwand.stroke();
 }

Im Beispiel stellen wir statt Balken Kreise zur Visualisierung dar. Dazu wird der Radius der Kreise („kreis_radius“) berechnet. Der Ausschlag definiert sich, wie auch beim Balkenspektrum über die Farbe, wobei hier noch ein zusätzlicher Alphakanal („farbe_alpha“) hinzukommt. Per „strokeStyle()“ bringen wir hier eine Rahmen-, aber keine Füllfarbe ein.  Außerdem wird die Linienstärke der Kreise („lineWidth“) ebenfalls dem jeweiligen Pegelausschlag angepasst. Per „arc()“ zeichnen wir den Kreis, mit „stroke()“ erhält er seine Farbe.

audiocontext_spektrum_beispiel_alternativ
Alternative Darstellungsform mit Kreisen statt Balken

Das hier dargestellte Audiospektrum ist nur ein relativ simples Beispiel. Es können natürlich auch wesentlich komplexere Visualisierungen entwickelt werden. Dennoch denke ich, Sie konnten hier einen soliden Einstieg in das Thema mitnehmen. Habe ich etwas Wichtiges übersehen?

(dpe)

Denis Potschien

Denis Potschien ist seit 2005 freiberuflich als Kommunikationsdesigner tätig, seit Anfang 2010 im Kreativkonsulat in Iserlohn, einem Büro für Gestaltung und Kommunikation. Dort betreut er kleine und mittelständische Unternehmen ebenso wie kommunale Körperschaften und Organisationen aus Südwestfalen und dem Ruhrgebiet. Als Webdesigner und -entwickler gehören HTML5 und CSS3 zu seinen Kernthemen, weshalb er dazu 2013 ein Buch geschrieben hat. „Pure HTML5 und CSS3“ richtet sich an alle, die Vorkenntnisse haben, sich aber bisher mit HTML5 und CSS3 nicht oder nur am Rande beschäftigt haben.

Sortiert nach:   neueste | älteste | beste Bewertung
Tim
Gast

mir fehlt irgendwie ein Link zum ersten Teil. Eine anzutestende Demo wäre auch cool. Abgesehen davon aber vielen Dank für den hilfreichen Artikel.

Andreas
Gast

Interessant, leider funktioniert es bei mir nicht (Chrome 38 Win7x64).
Konsole: Uncaught InvalidStateError: Failed to execute ‘createMediaElementSource’ on ‘AudioContext’: invalid HTMLMedialElement.
Javascript ist im Head.

Andreas
Gast

Okay, wenn das script nach audio und canvas funktioniert es sofort!

wpDiscuz