Noise Erstellen eines Synthesizers für Retro-Soundeffekte - Audioprozessoren

Dies ist der letzte Teil unserer Tutorialserie zum Erstellen einer Synthesizer-basierten Audio-Engine, mit der Sounds für Spiele im Retro-Stil erzeugt werden können. Die Audio-Engine kann alle Sounds zur Laufzeit erzeugen, ohne dass externe Abhängigkeiten wie MP3-Dateien oder WAV-Dateien erforderlich sind. In diesem Lernprogramm fügen wir Unterstützung für Audioprozessoren hinzu und codieren a Verzögerungsprozessor was unseren Klängen einen abklingenden Echoeffekt hinzufügen kann.

Wenn Sie das erste Tutorial oder das zweite Tutorial dieser Serie noch nicht gelesen haben, sollten Sie dies tun, bevor Sie fortfahren.

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.


Audioprozessor-Demo

In diesem letzten Tutorial werden wir hinzufügen Audioprozessoren zur Core Engine und zum Erstellen eines einfachen Verzögerungsprozessors. Die folgende Demonstration zeigt den Verzögerungsprozessor in Aktion:

In dieser Demonstration wird nur ein Sound gespielt, aber die Frequenz des Sounds wird zufällig festgelegt, und die von der Engine generierten Audio-Samples werden durch einen Verzögerungsprozessor geschoben, wodurch der Echo-Effekt nachlässt.


AudioProcessor Klasse

Als erstes müssen wir eine Basisklasse für die Audioprozessoren erstellen:

Paketrauschen public class AudioProcessor // public var aktiviert: Boolean = true; // public function AudioProcessor () if (Object (this) .constructor == AudioProcessor) throw new Fehler ("AudioProcessor-Klasse muss erweitert werden");  // interner Funktionsprozess (Beispiele: Vektor. ): ungültig 

Wie Sie sehen, ist die Klasse sehr einfach. es enthält ein internes verarbeiten() Methode, die von der aufgerufen wird AudioEngine Klasse, wenn Proben verarbeitet werden müssen, und eine öffentliche aktiviert Eigenschaft, mit der der Prozessor ein- und ausgeschaltet werden kann.


AudioDelay Klasse

Das AudioDelay Klasse ist die Klasse, die die Audioverzögerung tatsächlich erstellt, und erweitert die AudioProcessor Klasse. Hier ist die grundlegende leere Klasse, mit der wir arbeiten werden:

Paketrauschen public class AudioDelay erweitert AudioProcessor // öffentliche Funktion AudioDelay (time: Number = 0.5) this.time = time; 

Das Zeit Das an den Klassenkonstruktor übergebene Argument ist die Zeit (in Sekunden) des Delay Tap, dh die Zeit zwischen jeder Audio-Verzögerung.

Nun fügen wir die privaten Eigenschaften hinzu:

private var m_buffer: Vektor. = neuer Vektor.(); private var m_bufferSize: int = 0; private var m_bufferIndex: int = 0; private var m_time: Anzahl = 0,0; private var m_gain: Anzahl = 0,8;

Das m_buffer Der Vektor ist im Grunde eine Rückkopplungsschleife: Er enthält alle an den gesendeten Audio-Samples verarbeiten und diese Samples werden kontinuierlich modifiziert (in diesem Fall in der Amplitude reduziert) m_bufferIndex durchläuft den Puffer. Das wird Sinn machen, wenn wir an der verarbeiten() Methode.

Das m_bufferSize und m_bufferIndex Eigenschaften werden verwendet, um den Status des Puffers zu verfolgen. Das m_time Eigenschaft ist die Zeit des Verzögerungsabgriffs in Sekunden. Das m_gain property ist ein Multiplikator, mit dem die Amplitude der gepufferten Audio-Samples im Laufe der Zeit reduziert wird.

Diese Klasse hat nur eine Methode, und dies ist die interne verarbeiten() Methode, die das überschreibt verarbeiten() Methode in der AudioProcessor Klasse:

Interner Override-Funktionsprozess (Beispiele: Vector. ): void var i: int = 0; var n: int = samples.length; var v: Anzahl = 0,0; // während ich < n )  v = m_buffer[m_bufferIndex]; // grab a buffered sample v *= m_gain; // reduce the amplitude v += samples[i]; // add the fresh sample // m_buffer[m_bufferIndex] = v; m_bufferIndex++; // if( m_bufferIndex == m_bufferSize )  m_bufferIndex = 0;  // samples[i] = v; i++;  

Schließlich müssen wir die Getter / Setter für den Privatbereich hinzufügen m_time und m_gain Eigenschaften:

öffentliche Funktion get time (): Number return m_time;  public function set time (Wert: Anzahl): void // klemmt die Zeit auf den Bereich 0.0001 - 8.0 Wert = Wert < 0.0001 ? 0.0001 : value > 8,0? 8.0: Wert; // Die Puffergröße muss nicht geändert werden, wenn sich die Zeit nicht geändert hat if (m_time == value) return;  // Stelle die Zeit ein m_time = value; // aktualisiere die Puffergröße m_bufferSize = Math.floor (44100 * m_time); m_buffer.length = m_bufferSize; 
öffentliche Funktion get gain (): Number return m_gain;  public function set gain (value: Number): void // klemmt die Verstärkung auf den Bereich 0.0 - 1.0 m_gain = value < 0.0 ? 0.0 : value > 1,0? 1,0: Wert; 

Glaube oder nicht, das ist das AudioDelay Klasse abgeschlossen. Audioverzögerungen sind eigentlich sehr einfach, wenn Sie die Rückkopplungsschleife (die m_buffer Eigenschaft) funktioniert.


Aktualisieren der AudioEngine Klasse

Das letzte, was wir tun müssen, ist das Update AudioEngine Klasse, so dass Audioprozessoren hinzugefügt werden können. Fügen Sie zunächst einen Vektor hinzu, um die Audioprozessor-Instanzen zu speichern:

statische private var m_processorList: Vektor. = neuer Vektor.();

Hinzufügen und Entfernen von Prozessoren zum und vom AudioEngine Klasse werden wir zwei öffentliche Methoden verwenden:

AudioEngine.addProcessor ()

statische öffentliche Funktion addProcessor (Prozessor: AudioProcessor): void if (m_processorList.indexOf (Prozessor) == -1) m_processorList.push (Prozessor); 

AudioEngine.removeProcessor ()

statische öffentliche Funktion removeProcessor (Prozessor: AudioProcessor): void var i: int = m_processorList.indexOf (Prozessor); if (i! = -1) m_processorList.splice (i, 1); 

Einfach genug - all diese Methoden machen das Hinzufügen und Entfernen AudioProcessor Instanzen zu oder von der m_processorList Vektor.

Die letzte von uns hinzugefügte Methode führt die Liste der Audioprozessoren durch und leitet, wenn der Prozessor aktiviert ist, Audio-Samples an den Prozessor verarbeiten() Methode:

statische private Funktion processSamples (): void var i: int = 0; var n: int = m_processorList.length; // während ich < n )  if( m_processorList[i].enabled )  m_processorList[i].process( m_sampleList );  i++;  

Nun ist es an der Zeit, das letzte Code-Bit hinzuzufügen. Dies ist eine einzige Codezeile, die dem privaten Code hinzugefügt werden muss onSampleData () Methode in der AudioEngine Klasse:

if (m_soundChannel == null) while (i < n )  b.writeFloat( 0.0 ); b.writeFloat( 0.0 ); i++;  return;  // generateSamples(); processSamples(); // while( i < n )  s = m_sampleList[i] * m_amplitude; b.writeFloat( s ); b.writeFloat( s ); m_sampleList[i] = 0.0; i++; 

Die hervorgehobene Codezeile ist die, die der Klasse hinzugefügt werden muss. es ruft einfach die processSamples () Methode, die wir zuvor hinzugefügt haben.


Fazit

Das ist, wie sie sagen, das. Im ersten Tutorial haben wir uns verschiedene Wellenformen und die digitale Speicherung von Schallwellen angesehen. Dann haben wir im zweiten Tutorial den Code für die Core-Audio-Engine konstruiert, und nun haben wir die Dinge mit dem Hinzufügen von Audioprozessoren abgeschlossen.

Es gibt noch viel mehr, die mit diesem Code oder einer Variation dieses Codes erledigt werden können. Wichtig ist jedoch, dass die Audio-Engine zur Laufzeit sehr viel Arbeit zu leisten hat. Wenn Sie eine Audio-Engine zu weit treiben (und das ist einfach zu bewerkstelligen), kann die Gesamtleistung Ihres Spiels als Folge leiden - selbst wenn Sie eine Audio-Engine in einen eigenen Thread (oder ActionScript 3.0-Worker) verschieben, ist sie dennoch glücklich Biss Chunks aus der CPU, wenn Sie nicht aufpassen.

Viele professionelle und nicht so professionelle Spiele führen jedoch zur Laufzeit viele Audiobearbeitungen durch, da dynamische Soundeffekte und Musik in einem Spiel das Gesamterlebnis erheblich verbessern können und den Spieler tiefer in das Spiel einbeziehen können Welt. Die Audio-Engine, die wir in dieser Serie von Tutorials zusammengestellt haben, könnte genauso gut mit regulären (nicht generierten) Soundeffekt-Samples arbeiten, die aus Dateien geladen werden: Im Wesentlichen ist alles digitale Audio eine Sequenz von Samples in seiner grundlegendsten Form.

Zum Schluß noch einmal zu denken: Audio ist ein sehr wichtiger Aspekt des Spieledesigns. Es ist genauso wichtig und kraftvoll wie die visuelle Seite der Dinge und sollte nicht in letzter Minute zusammen geworfen oder in ein Spiel verankert werden Entwicklung, wenn Sie sich wirklich für die Produktionsqualität Ihrer Spiele interessieren. Nehmen Sie sich Zeit für das Audiodesign für Ihre Spiele, und Sie werden belohnt.

Ich hoffe, Ihnen hat diese Serie von Tutorials gefallen und Sie können etwas Positives davon nehmen: Selbst wenn Sie von jetzt an nur noch ein wenig mehr an das Audio in Ihren Spielen denken, dann habe ich meine Arbeit erledigt.

Der gesamte Quellcode der Audio-Engine ist im Quellendownload verfügbar.

Habe Spaß!