Registriert: Do Jun 28, 2007 17:58 Beiträge: 193
Programmiersprache: Pascal, C
Audorra - Digitale 3D Audiobibliothek
Was ist das, bzw. was wird es werden? Audorra ist eine Cross Plattform Audiobibliothek für Pascal, die es ermöglicht Musik und Soundeffekte in Spielen (oder anderen Audio-Anwendungen) wiederzugeben. Dabei liegt volle Unterstützung für 3D-Surround Sound und Positionierung von Audioquellen im 3D-Raum vor. Audorra ist modular aufgebaut: Sowohl die Ausgabebibliothek ("driver", also z.B. WaveOut, DirectSound oder OpenAL) als auch die Decoder können über ein Pluginsystem statisch oder dynamisch gelinkt werden.
Warum dieses Projekt? Audorra soll als Ergänzung zu meiner 2D-Grafikbibliothek Andorra 2D und zu meiner Medienbibliothek Acinerella gesehen werden. Außerdem ist für Pascal abgesehen von ACS (welches keinen 3D Sound unterstützt) keine OpenSource Audiobibliothek vorhanden, oftmals wird FMOD oder die BASS verwendet - ein Misstand, der schleunigst behoben werden sollte.
Registriert: Do Jun 28, 2007 17:58 Beiträge: 193
Programmiersprache: Pascal, C
It's done in Software Nein, der 3D-Audioteil von Audorra verwendet nicht OpenAL, sondern einen eigenen 3D-Audio Softwarerenderer. Diese Neuigkeit schockiert vielleicht den einen oder anderen - Doch die Gründe dafür sollten recht einleuchtend sein:
Für meine OnBoard-Soundkarte (und vermutlich viele andere) ist kein funktionierender Hardware-OpenAL Treiber vorhanden, es würde sowieso Software verwendet werden - was mehr schlecht als recht funktioniert
Im oberen Fall ist OpenAL nur ein Layer vor anderen Audio-APIs (DirectSound, ALSA, PulseAudio), was die Latenzzeit leider stark erhöht. Der Zugriff auf andere Audio-APIs kann dann doch auch direkt aus der Anwendung erfolgen.
Starke Einschränkungen durch die API (kein HD-Audio (Mehrkanalton, 24- oder 32-Bit), begrenzte Anzahl an Soundquellen.
Viel mehr Freiheiten, wenn man es in Software macht (Phasenverschiebung, Echos)
Überall die gleichen Ergebnisse
Heutige Hauptprozessoren machen das bisschen Audio-Berechnung mit links: Meine aktuellen Tests benötigen nur ganze 250us pro 12,5ms Audio und der Prozess dümpelt mit 0%-CPU Auslastung recht weit unten in der Prozessliste - dabei wird schon eifrig die Sample-Rate umgerechnet sowie Phasenverschiebung und Dopplereffekt berücksichtigt (wie genau das funktioniert erkläre ich unten).
Alle Besitzer von Edelsoundkarten werden nun vermutlich aufschreien, da sie keinen Vorteil daraus ziehen können (abgesehen von guten D/A-Wandlern). Pech gehabt .
Doch wie funktioniert nun der 3D-Audio Renderer? Wie in OpenAL oder DirectSound3D können Soundquellen in einem virtuellen Raum verteilt werden. Je nach Winkel zu dem Betrachter werden die verschiedenen Lautsprecherlautsärken berechnet (siehe: http://wiki.delphigl.com/index.php/3D_A ... berechnung):
Um Phasenverschiebung/Dopplereffekt berücksichtigen zu können, wende ich den folgenden Trick an: Die Audiodaten werden nicht als reine Sampledaten im Speicher abgelegt, sondern eine passende (und sehr schnell zu berechnende) Spline-Funktion (siehe: http://audorra.sourceforge.net/index.ph ... erpolation). Nun kann nicht nur auf Sample-Basis sondern auf Zeitbasis auf die Audiodaten zugegriffen werden: Hierdurch wird "kostenlos" die Samplerate-Conversion durchgeführt, Pitch, Phasenverschiebund und Dopplereffekt berechnet. Und das alles quasi zum "Nulltarif".
Die Spline-Daten werden zudem in einem 5-10sec großen Ringpuffer behalten, sodass jeweils in die "Zukunft" als auch die "Vergangenheit" der Audioquelle "gesehen" werden kann. Hierdurch können Effekte wie Echo recht einfach hinzugefügt werden.
Noch nicht implementiert ist die Abschwächung der Soundquelle durch Wände. Ich möchte hier mit einem einfachen Raytracing arbeiten, wobei für die Wände jeweils Absorptionsfaktoren festgelegt werden. In einem weiteren Schritt möchte ich durch Hinzufügen von "Kindersoundquellen", welche automatisch von den Soundquellen ausgesandt werden, Echos hinzufügen. Jedoch soll letzeres erst in einer der nächsten Versionen erscheinen.
Ersteinmal möchte ich die Hauptfeatures stabil bekommen.
Registriert: Do Jun 28, 2007 17:58 Beiträge: 193
Programmiersprache: Pascal, C
Nach einigen Optimierungen konnte ich die Berechnungszeit meines 3D-Softwarerenderes von 250us auf durchschnittlich 185us pro 12,5ms Audiodaten (44100 Hz, 6 Kanäle) drücken: Ich hatte in meinem Ringpuffer unnötigerweise eine TCriticalSection und mehrere try-finally Konstrukte verwendet. Hinzu kommen jedoch noch einmal pauschal ca. 60us für die Konvertierung von Single zu SmallInt, wodurch wir bei insgesammt 235us wären.
Unter anbetracht der Tatsache, dass mein einfacher Filtergraph (mit Lautstärkeregler und Kompressorfilter) schon (insgesammt) 130us für zwei Kanäle braucht, sind diese Werte nicht schlecht.
Registriert: Do Jun 28, 2007 17:58 Beiträge: 193
Programmiersprache: Pascal, C
Mein Dopplereffekt/Phasenverschiebungscode funktioniert nun auch sehr gut. Wie oben beschrieben tritt hierdurch keine (nennenswerte) Verlangsamung des Berechnungsprozesses ein.
Ich verfolge hierbei ein anderes, physikalisch korrekteres Modell als OpenAL: Dort wird zur Berechnung des Dopplereffekts für jede Soundquelle ein Geschwindigkeitsvektor benötigt. Die Phasenverschiebung, die aus dem Abstand von Tonquelle und Hörer sowie der Schallgeschwindigkeit entsteht, wird nicht berücksichtigt. Dabei ist genau diese der eigentliche Grund für den Dopplereffekt: Durch die Simulation der Phasenverschiebung entsteht zwangsläufig der Dopplereffekt (Proportional zur Ableitung der Phasenverschiebungsfunktion).
Um eine "flüssige" Audioausgabe zu erreichen wird für jede Soundquelle vor jedem (großen) Berechnungsschritt ein Event ausgelöst, in welchem die Position der Audioquelle aktualisiert werden muss. Dies ist notwendig, da sich die Soundquellen kontinuierlich bewegen müssen um den Dopplereffekt korrekt erzeugen zu können (Ableitung der Phasenverschiebungsfunktion würde sonst kurzzeitig Null und somit auch der Dopplereffekt kurz stoppen, was sich nicht sehr gut anhört).
Registriert: Do Jun 28, 2007 17:58 Beiträge: 193
Programmiersprache: Pascal, C
So, ich habe das Ganze ein wenig Umstrukturiert ("Refactort" ) und die Soundinformationen und Emitter getrennt. Man kann sich das ungefähr folgendermaßen vorstellen:
An einen Verstärker (Soundinformationen) können beliebig viele Lautsprecher (Emitter) angeschlossen werden. Diese können entsprechend im Raum verteilt werden.
Mein erster Test hat mich mal wieder erstaunen lassen, wie glatt das Ganze läuft: Ich habe einen Raum mit 200m Größe erstellt und einen beweglichen Lautsprecher (an die Maus gekoppelt, ich habe nur eine Konsolenanwendung) und einen festen Lautsprecher bei (0|-100). Das Programm gestartet und sofort hatte ich ein realistisches Echo! Physikalisch (einigermaßen) korrekte Simulationen haben doch ihre Vorteile...
Nun muss ich den Prozess nur noch wieder etwas zeitoptimieren...
Registriert: Do Jun 28, 2007 17:58 Beiträge: 193
Programmiersprache: Pascal, C
In den letzten Tagen habe ich noch die positionsabhängige Abschwächung des Audiosignals sowie "globale" Sounds eingebaut. Nun muss ich dort "nur" noch die Lautstärke pro Kanal regelbar machen, außerdem sind Bewegung und Orientierung des Listeners umzusetzen.
Anschließend muss ich mir eine gute Kapselung für die 3D-Audioklassen überlegen - momentan sind diese nämlich weder Threadsicher (=> Performance) und sie besitzen noch keinerlei Anbindung an die eigentliche Bibliothek - es handelt sich ausschließlich um Klassen zur Berechnung von 3D-Audiodaten. In meiner Testanwendung streame ich die Daten "manuell" an den Ausgabetreiber.
Ich plane den 3D-Renderer irgendwie in mein Filtergraphsystem zu integrieren - nur wie genau, darüber habe ich mir noch keine Gedanken gemacht - auch nicht darüber, wie ich meine Emitter- und Listener-Klassen am besten in ein Spiel einbauen würde. Dafür möchte ich eine entsprechende Demoapplikation schreiben.
Wenn dann alles noch einmal "sauber" gemacht worden ist und enstprechend dokumentiert, wird es das erste "offizielle" Release geben.
Registriert: Do Jun 28, 2007 17:58 Beiträge: 193
Programmiersprache: Pascal, C
Hallo,
ich habe heute mein Filtergraphsystem und meinen 3D-Audiorenderer "verschmolzen". Gelöst habe ich das Problem eine Klasse namens "TAu3DSoundAdapter": Diese Klasse kann in einen bestehenden Filtergraphen eingebunden werden und verbindet sich wiederrum mit dem 3D-Audiorenderer. Somit kann nun die ganz normale "TAuPlayer"-Klasse verwendet werden um die Audiodaten im 3D-Raum zu rendern:
//Ein ganz normales "TAuPlayer"-Objekt erstellen und über den Adapter mit dem Renderer verbinden
FPlayer := TAuPlayer.Create(FAudio, FAdapter);//Normalerweise muss der "FAdapter"-Parameter nicht angegeben werden - dann werden die Daten über einen eigenen Ausgabestream ausgegeben...
FPlayer.LoadFromFile(ParamStr(1));
FPlayer.Open;
FPlayer.Play;
//Einen einfachen Emitter für den Sound erstellen
FEmitter := TAu3DEmitter.Create(FAdapter.Sound);
end;
Um den Renderer mit dem Spiel zu synchronisieren werde ich eine Funktion "Lock/Unlock" in den Renderer einbauen, die Thread-Konflikte verhindern. Jedigliche verwendung des Renderers (also auch das einstellen von Parametern) muss folgendermaßen geschehen:
Code:
FRenderer.Lock;
try
FAdapter.Sound.Pitch:=1.5;
FEmitter.Position:= AcVector3(0.0,0.0,1.0);
finally
FRenderer.Unlock;
end;
Im Anhang ist ein Bildchen, das den neuen Weg des Filtergraphs zeigt (Blau sind Filtergraphelemente dargestellt)
Dateianhänge:
Dateikommentar: Audio Pipeline 3D_Sound_Pipeline.png [54.4 KiB]
Noch nie heruntergeladen
Registriert: Do Jun 28, 2007 17:58 Beiträge: 193
Programmiersprache: Pascal, C
Hallo,
mir war es heute möglich die Performance meines Systems um ca. 1/3 zu steigern. Dabei habe ich einige 80-Bit Fließkommazahlen durch 64-Bit Festkommawerte ersetzt.
Zum Hintergrund: Wie ich bereits oben geschildert habe, ermöglicht mir meine Splineinterpolation zeitbasierten Zugriff auf die Audiodaten. Bisher habe ich hierbei in Sekunden gerechnet. Um trotzdem jedes Sample einzeln Ansteuern zu können und über die Zeit hinweg keine nennenswerten (!) Abweichungen zu bekommen habe ich mit 80-Bit Fließkommazahlen (Extended) gerechnet. Leider musste beim Lookup jedes Samplewertes ein Zeitstempel in eine Speicherstelle und einen t-Wert für die Splinefunktion umgerechnet werden. Genau diese Umrechnung benötigte jedoch jede Menge Zeit.
Nun Rechne ich mit Int64 auf Samplebasis, wobei die letzten 16-Bit der Variable den Festkommateil darstellen. Dies geht nicht nur deutlich flotter, sondern ist auch noch nach den maximal Indexierbaren 2231 Jahren Audiowiedergabe (bei 96kHz, sollte glaube ich reichen) genauso genau wie nach dem ersten Sample.
Zum Vergleich: Die Berechnung von 25ms eines Musikstückes bei 96kHz, 6 Kanäle, dauerte zuvor 900us, nun lediglich 600us.
Andreas
Update: Um Vergleichswerte zu haben: Anstatt der oben erwähnten 185us bei 12,5ms Audio und 44,1kHz benötige ich nun 150us.
Registriert: Do Jun 28, 2007 17:58 Beiträge: 193
Programmiersprache: Pascal, C
Ein bisschen WASAB(P)I schadet nie...
Hallo, ich habe gestern Unterstützung für WASAPI (Windows Audio Session API) für Windows Vista und 7 eingebaut - WASAPI hat den Vorteil, dass es sich um die unterste Abstraktionsebene über dem Treiber handelt. Somit kann eine niedrige Latenzzeit erreicht werden - momentan bewege ich mich (mit meiner Implementierung, theoretisch ist garantiert mehr drin) bei 20ms (zum Vergleich: DirectSound funktionierte nur bei 100ms ohne Aussetzer). Auch Multichannel-Audio wird von dieser Schnittstelle unterstützt. Einzige Hürde hierbei: Bei DirectSound/WaveOut genügte es die "ChannelMask" einfach mit Einsen zu Füllen - WASAPI reagierte hierauf etwas allergisch. Der Nachteil des ganzen ist momentan, dass das Ganze nur im Exklusiven Modus richtig funktioniert - für Spiele sollte dies jedoch eher ein Vorteil sein.
Da ich keine Lust hatte die Header für Pascal zu übersetzen habe ich mit Visual Studio eine einfache Wrapper-DLL für die WASAPI Schnittstelle geschrieben - entgegen allen Befürchtungen war das sehr einfach. Die DLL exportiert genau 6 Funktionen, was den Header sehr schlank macht:
Die Bibliothek wird dynamisch geladen und ist (ohne Runtime) mit 8 KB sehr schlank - somit kann sie auch ohne Bedenken mit allen Programmen mitgeliefert werden - unter Windows XP/2000 kann das Plugin einfach nicht geladen werden und somit wird ein Fallback verwendet.
Registriert: Do Jun 28, 2007 17:58 Beiträge: 193
Programmiersprache: Pascal, C
Libao Ich habe heute und gestern Unterstützung für "libao" hinzugefügt - das Ganze läuft (abgesehen von WASAPI (20ms)) wie alle anderen Ausgabeschnittstellen mit 100ms Latenzzeit. Zudem habe ich begonnen Dokumentation und Tutorials für die Bibliothek zu schreiben.
Zudem sollte ich nicht verschweigen, dass ich sehr angenehm überrascht von der neuen Lazarus-Version bin: Der Codeeditor sieht jetzt nicht nur aus wie Delphi, sondern fühlt sich fast so an. Nur hier und da funktioniert die Codevervollständigung nicht ganz so wie sie sollte - aber ich denke das wird noch. Den GUI-Editor habe ich nicht getestet, den brauche ich aber auch nicht . Also Appell an alle, die Lazarus ersteinmal zur Seite gelegt hatten: Ausprobieren!
Guten Rutsch ins neue Jahr wünscht euch allen, Andreas
PS: Das Wichtigste habe ich doch glatt vergessen: 1. libao läuft unter Linux! Deshalb habe ich jetzt nicht nur OpenAL für Cross-Platform Audioausgabe. Wurde auch mal Zeit. Habe ich schon erwähnt, dass ich kein großer Fan von OpenAL bin? 2. libao ist deshalb so praktisch, weil hierbei über eine gemeinsame Schnittstelle sehr viele verschiedene APIs angesprochen werden. Bei mir sind das momentan: - PulseAudio - ALSA - OSS - ESounD 3. libao ist übrigens von xiph.org, den "Machern" von Vorbis und Theora 4. libao ist auf den meisten Linuxsystemen bereits installiert. 5. Damit funktioniert nun auch Multichannel-Audioausgabe. Auch unter Linux. Perfekt für meinen 3D-Audio-Softarerenderer. OpenAL kann das (also Multichannel-Audioausgabe) übrigens nicht, außer mit irgendwelchen Extensions, die nur vom DirectSound-OpenAL-Softwarerenderer und irgendwelchen seltenen Soundkarten unterstützt werden. Habe ich übrigens schon erwähnt, dass ich OpenAL nicht mag? Leute, verwendet Audorra wenns' fertig ist
Registriert: Do Jun 28, 2007 17:58 Beiträge: 193
Programmiersprache: Pascal, C
Audio-CD und Soundeffekte
Ich habe nun erfolgreich die Klassen "TAuStaticSound" und "TAuSoundList" in meinen 3D-Audiorenderer migriert. Die Klasse "TAuStaticSound" kümmert sich hierbei um das Laden und Speichern von Soundeffekten und stellt ein TAu3DSound Objekt bereit. Soll der Sound wiedergegeben werden, so muss einfach ein Emitter erstellt werden, der mit diesem Soundobjekt verknüpft ist. Der Emitter kann wie gewünscht im Raum verteilt werden.
Hier ein kurzer Beispielcode:
Code:
var
em: TAu3DEmitter;
begin
Au3DAudio.Lock;
try
em := TAu3DEmitter.Create(AuSoundList.Find('bumm').Sound);
Um Audio-CDs in einer Applikation wiedergeben zu können, muss einfach die Unit "AuCDAudio.pas" eingebunden werden. CDs können nun durch öffnen der URL "cdda://F/12" (wobei "F" für das CD-Laufwerk steht und "12" für die Titelnummer) geöffnet werden. Zudem ist ein "Dekoder" für .cda Dateien vorhanden, der diese auf eben eine solche URL umleitet.
Edit: Habe das URL Schema auf "cdda://F/?track=12" geändert, danke für den Hinweis an LordHorazont!
Registriert: Do Jun 28, 2007 17:58 Beiträge: 193
Programmiersprache: Pascal, C
Wir sind Einsatzbereit!
Gute Neuigkeiten! Ich glaube Audorra nun in einem Stadium zu wissen, das ich guten Gewissens "Einsatztauglich" nennen kann - abgesehen von der Dokumentation. Aus diesem Grund - und auch nur aus diesem Grund - wird es vorerst auch kein offizielles Version 1.0 Beta Release geben - die aktuellste Version gibt es wie immer im SVN. Außerdem muss ich noch ein paar Tests unter Linux/Lazarus durchführen.
Bevor ich die ganzen anderen Features einbaue möchte ich erst einmal die aktuelle Codebasis stabilisieren und die Dokumentation dazu schaffen.
Es wäre sehr schön, wenn der eine oder andere hier die Bibliothek in seinem Projekt einsetzen könnte und mir Feedback über die Verwendbarkeit bzw. Vorschläge zur Verbesserung gibt.
Ich habe zudem eine (noch sehr rudimentäre) Demo mit dem Namen "Soundscape" erstellt, mit der sich Sounds in den Speicher laden, in einem virtuellen Raum positionieren und schlussendlich wiedergeben lassen. Einen Screenshot der Anwendung habe ich angehängt, die Demo gibt's im SVN.
Auch Support für die OGG Vorbis-Wiedergabe mithilfe der libvorbisfile ist nun vorhanden (AuVorbis.pas).
Ich freue mich schon auf eure Rückmeldungen, Andreas
Dateianhänge:
Dateikommentar: Screenshot der "Soundscape" Demo soundscape_demo.png [17.82 KiB]
Noch nie heruntergeladen
Registriert: Do Jun 28, 2007 17:58 Beiträge: 193
Programmiersprache: Pascal, C
So, ich habe nun die (mittlerweile) zweite Bugfixversion hochgeladen, die einige Probleme mit dem 3D-Audiosystem behebt und Kompatibilität mit Delphiversionen kleiner Delphi 7 herstellt. Näheres kann im Meinungsthread zum Projekt nachgelesen werden.
Das Wiki baue ich momentan lokal bei mir um. Leider erweist sich das SF-Wiki als ziemlich lahm. Ich verwende nun Dokuwiki - dieses lässt sich (sammt Inhalten) sehr bequem und einfach auf einen neuen Server umziehen.
Mitglieder in diesem Forum: 0 Mitglieder und 37 Gäste
Du darfst keine neuen Themen in diesem Forum erstellen. Du darfst keine Antworten zu Themen in diesem Forum erstellen. Du darfst deine Beiträge in diesem Forum nicht ändern. Du darfst deine Beiträge in diesem Forum nicht löschen. Du darfst keine Dateianhänge in diesem Forum erstellen.