Dies ist das erste einer Reihe von Tutorials, in denen eine auf Synthesizer basierende Audio-Engine erstellt wird, die Sounds für Spiele im Retro-Stil erzeugen kann. Die Audio-Engine erzeugt zur Laufzeit alle Sounds, ohne dass externe Abhängigkeiten wie MP3-Dateien oder WAV-Dateien erforderlich sind. Das Endergebnis wird eine funktionierende Bibliothek sein, die mühelos in Ihre Spiele eingefügt werden kann.
Bevor wir mit der Erstellung der Audio-Engine beginnen können, müssen wir einige Dinge verstehen. Dazu gehören die Wellenformen, mit denen die Audio-Engine die hörbaren Töne erzeugt, und wie Schallwellen in digitaler Form gespeichert und dargestellt werden.
Die in diesem Lernprogramm verwendete Programmiersprache ist ActionScript 3.0. Die verwendeten Techniken und Konzepte können jedoch problemlos in jede andere Programmiersprache übersetzt werden, die eine Low-Level-Sound-API bietet.
Sie sollten sicherstellen, dass Flash Player 11.4 oder höher für Ihren Browser installiert ist, wenn Sie die interaktiven Beispiele in diesem Lernprogramm verwenden möchten.
Die Audio-Engine, die wir erstellen werden, verwendet vier grundlegende Wellenformen (auch bekannt als periodisch Wellenformen, da sich ihre Grundformen periodisch wiederholen), die alle sowohl bei analogen als auch bei digitalen Synthesizern sehr häufig vorkommen. Jede Wellenform hat ihre eigenen hörbaren Eigenschaften.
Die folgenden Abschnitte bieten eine visuelle Darstellung jeder Wellenform, ein hörbares Beispiel für jede Wellenform und den Code, der erforderlich ist, um jede Wellenform als Array von Abtastdaten zu erzeugen.
Die Pulswelle erzeugt einen scharfen und harmonischen Klang.
Um ein Array von Werten (im Bereich von -1,0 bis 1,0) zu erzeugen, die eine Pulswelle darstellen, können wir den folgenden Code verwenden, wobei n
ist die Anzahl der Werte, die zum Füllen des Arrays erforderlich sind, ein
ist das Array und p
ist die normalisierte Position innerhalb der Wellenform:
var i: int = 0; var n: int = 100; var p: Anzahl; während ich < n ) p = i / n; a[i] = p < 0.5 ? 1.0 : -1.0; i ++;
Die Sägezahnwelle erzeugt einen scharfen und harten Klang.
Um ein Array von Werten (im Bereich von -1,0 bis 1,0) zu erzeugen, die eine Sägezahnwelle darstellen, können wir den folgenden Code verwenden, wobei n
ist die Anzahl der Werte, die zum Füllen des Arrays erforderlich sind, ein
ist das Array und p
ist die normalisierte Position innerhalb der Wellenform:
var i: int = 0; var n: int = 100; var p: Anzahl; während ich < n ) p = i / n; a[i] = p < 0.5 ? p * 2.0 : p * 2.0 - 2.0; i ++;
Die Sinuswelle erzeugt einen sanften und reinen Klang.
Um ein Array von Werten (im Bereich von -1.0 bis 1.0) zu erzeugen, die eine Sinuswelle darstellen, können wir den folgenden Code verwenden, wobei n
ist die Anzahl der Werte, die zum Füllen des Arrays erforderlich sind, ein
ist das Array und p
ist die normalisierte Position innerhalb der Wellenform:
var i: int = 0; var n: int = 100; var p: Anzahl; während ich < n ) p = i / n; a[i] = Math.sin( p * 2.0 * Math.PI ); i ++;
Die Dreieckswelle erzeugt einen sanften und harmonischen Klang.
Um ein Array von Werten (im Bereich von -1,0 bis 1,0) zu erzeugen, die eine Dreieckswelle darstellen, können wir den folgenden Code verwenden, wobei n
ist die Anzahl der Werte, die zum Füllen des Arrays erforderlich sind, ein
ist das Array und p
ist die normalisierte Position innerhalb der Wellenform:
var i: int = 0; var n: int = 100; var p: Anzahl; während ich < n ) p = i / n; a[i] = p < 0.25 ? p * 4.0 : p < 0.75 ? 2.0 - p * 4.0 : p * 4.0 - 4.0; i ++;
Hier ist eine erweiterte Version von Zeile 6:
wenn P < 0.25) a[i] = p * 4.0; else if (p < 0.75) a[i] = 2.0 - (p * 4.0); else a[i] = (p * 4.0) - 4.0;
Zwei wichtige Eigenschaften einer Schallwelle sind die Amplitude und Frequenz der Wellenform: Diese bestimmen das Volumen und Tonhöhe des Klangs. Die Amplitude ist einfach der absolute Spitzenwert der Wellenform, und die Frequenz ist die Anzahl der Wiederholungen der Wellenform pro Sekunde, die normalerweise in Hertz (Hz) gemessen wird..
Das folgende Bild ist eine 200 Millisekunden-Momentaufnahme einer Sägezahnwellenform mit einer Amplitude von 0,5 und einer Frequenz von 20 Hertz:
Um Ihnen eine Vorstellung davon zu geben, wie die Frequenz einer Wellenform direkt mit der Tonhöhe des hörbaren Tons zusammenhängt, erzeugt eine Wellenform mit einer Frequenz von 440 Hertz die gleiche Tonhöhe wie die Standard-A4-Note (mittleres A) eines modernen Konzertflügels. In Anbetracht dieser Häufigkeit können wir die Häufigkeit einer Note mithilfe des folgenden Codes berechnen:
f = Math.pow (2, n / 12) * 440,0;
Das n
Variable in diesem Code ist die Anzahl der Noten von A4 (mittleres A) bis zu der Note, die uns interessiert. Um beispielsweise die Frequenz von A5 zu ermitteln, eine Oktave über A4, würden wir den Wert von festlegen n
zu 12
denn A5 ist 12 Noten über A4. Um die Frequenz von E2 zu finden, würden wir den Wert von setzen n
zu -5
weil E2 5 Noten unter A4 liegt. Wir können auch die Umkehrung ausführen und eine Note (relativ zu A4) für eine bestimmte Frequenz finden:
n = Math.round (12.0 * Math.log (m / 440.0) * Math.LOG2E);
Der Grund für das Berechnen dieser Berechnungen ist, dass die Notenfrequenzen logarithmisch sind. Durch Multiplizieren einer Frequenz mit zwei wird eine Note um eine Oktave nach oben verschoben, während eine Frequenz durch zwei geteilt wird, um eine Note um eine Oktave nach unten.
In der digitalen Welt müssen Schallwellen als binäre Daten gespeichert werden. Die übliche Art und Weise, dies zu tun, besteht darin, periodische Momentaufnahmen (oder Samples) einer Schallwelle zu machen. Die Anzahl der Wave-Samples, die für jede Sekunde einer Klangdauer genommen werden, wird als bezeichnet Beispielrate, Ein Sound mit einer Sample-Rate von 44100 enthält also pro Sekunde der Länge des Sounds 44100 Wave-Samples (pro Kanal).
Das folgende Bild zeigt, wie eine Schallwelle abgetastet werden kann:
Die weißen Flecken in diesem Bild repräsentieren die Amplitudenpunkte der Welle, die in einem digitalen Format abgetastet und gespeichert werden. Sie können sich dies als Auflösung eines Bitmap-Bildes vorstellen: Je mehr Pixel ein Bitmap-Bild enthält, desto mehr visuelle Informationen können gespeichert werden, und je mehr Informationen ergeben größere Dateien (Dateikomprimierung vorerst ignorieren). Gleiches gilt für digitale Sounds: Je mehr Wave-Samples eine Sounddatei enthält, desto genauer ist die rekonstruierte Soundwelle.
Digitale Sounds haben nicht nur eine Sample-Rate, sondern auch eine Bitrate das wird in Bits pro Sekunde gemessen. Die Bitrate bestimmt, wie viele binäre Bits verwendet werden, um jeden Wellenabtastwert zu speichern. Dies ist ähnlich der Anzahl von Bits, die zum Speichern von ARGB-Informationen für jedes Pixel in einem Bitmap-Bild verwendet werden. Ein Sound mit einer Sample-Rate von 44100 und einer Bitrate von 705600 würde beispielsweise jedes seiner Wave-Samples als 16-Bit-Wert speichern. Dies lässt sich mit dem folgenden Code leicht genug berechnen:
bitsPerSample = bitRate / sampleRate;
Hier ist ein Arbeitsbeispiel mit den oben genannten Werten:
Spur (705600/44100); // "16"
Zu verstehen, was Klangbeispiele sind, ist hier das Wichtigste. Die Audio-Engine, die wir erstellen werden, muss Roh-Samples erzeugen und bearbeiten.
Eine weitere Sache, die wir beachten sollten, bevor wir mit der Programmierung der Audio-Engine beginnen, ist Modulatoren, Diese sind sowohl bei analogen als auch bei digitalen Synthesizern extrem verbreitet. Ein Modulator ist im Wesentlichen nur eine Standardwellenform, aber anstatt zur Erzeugung eines Klanges verwendet zu werden, werden sie üblicherweise verwendet, um eine oder mehrere Eigenschaften einer hörbaren Wellenform (z. B. ihre Amplitude oder Frequenz) zu modulieren..
Nehmen Vibrato, zum Beispiel. Vibrato ist eine regelmäßige pulsierende Tonhöhenänderung. Um diesen Effekt mit einem Modulator zu erzeugen, können Sie die Wellenform des Modulators auf eine Sinuswelle und die Frequenz des Modulators auf etwa 8 Hertz einstellen. Wenn Sie diesen Modulator dann an die Frequenz einer hörbaren Wellenform anschließen, führt dies zu einem Vibrato-Effekt - der Modulator würde die Frequenz (Tonhöhe) der hörbaren Wellenform achtmal pro Sekunde gleichmäßig anheben und absenken.
Mit der Audio-Engine, die wir erstellen werden, können Sie Modulatoren an Ihre Sounds anschließen, um eine Vielzahl von unterschiedlichen Effekten zu erzeugen.
Im nächsten Tutorial werden wir den Kerncode für die Audio-Engine erstellen und alles in Betrieb nehmen. Folgen Sie uns auf Twitter, Facebook oder Google+, um über die neuesten Beiträge auf dem Laufenden zu bleiben.