OpenAL

Wie im ersten Teil angekündigt, will ich ein bischen was zu OpenAL schreiben. OpenAL ist im Prinzip das „musikalische“ Gegenstück zu OpenGL und läßt sich auch entsprechend einfach benutzen. Die Dokumentation dazu gibts hier: creative. Einer der interessantesten Punkte in OpenAL ist, das man damit 3D Surround Sounds erzeugen kann.

Im ersten Teil geht es einfach mal nur darum, einen Sound aus OpenAL rauszukriegen:

Dafür sind folgende Schritte notwendig (Pseudo):

Sounddevice initialisieren
Puffer anlegen
Sound in den Puffer laden
eine SoundQuelle aus dem Puffer anlegen
verschiedene Soundeinstellungen vornehmen
Sound abspielen
Device wieder löchen

Was hier im Pseudocode relativ einfach aussieht, ist in der Praxis genau so ;-) Wie gesagt benötigen wir im ersten Schritt ein Sounddevice

Dazu haben wir 2 Möglichkeiten

  1. über alutInit(NULL, 0); (Dies nehmen wir)

Dies erzeugt ein Handle am StandardDevice, was soviel bedeutet wie, wir initialisieren die Standard Soundschnittstelle.

  1. der lange Weg in dem wir ein Device und ein Handle selbst auswählen und anlegen müssen

Da Entwickler ja von Haus aus, bequeme Menschen sind ;-), hab ich mich für den ersten Weg entschieden. Ok nachdem wir unser SoundDevice haben, legen wir einen Puffer an

	alGenBuffers(1, &Buffer);
    if (alGetError() != AL_NO_ERROR)
        return AL_FALSE;
das ist vergleichbar mit dem Anlegen einer Textur in OpenGL.

Wenn wir den Puffer angelegt haben, laden wir einen Sound

	NSString *path = [[NSBundle mainBundle]pathForResource:@"FancyPants" ofType:@"wav"];
    alutLoadWAVFile([path cString], &format, &data, &size, &freq, &loop);
 
	alBufferData(Buffer, format, data, size, freq);
    alutUnloadWAV(format, data, size, freq);
Im nächsten Schritt generieren wir eine Soundquelle (diese ist der eigentliche „Emitter“ der Soundausgabe, dazu gleich mehr)
  alGenSources(1, &Source);
 
    if (alGetError() != AL_NO_ERROR)
        return AL_FALSE;

Und zum Schluß machen wir noch verschiedene Einstellungen

 alSourcei (Source, AL_BUFFER,   Buffer   );	
 alSourcef (Source, AL_PITCH,    1.0f     );	
 alSourcef (Source, AL_GAIN,     1.0f     );	
 alSourcefv(Source, AL_POSITION, SourcePos);	
 alSourcefv(Source, AL_VELOCITY, SourceVel);	
 alSourcei (Source, AL_LOOPING,  loop     );

Wie gesagt ist OpenAL eine 3D Sound Lib, das bedeutet das wir uns auch darum kümmern müssen, wo der Sound aus dem 3D Raum kommt. Dazu gibts einmal einen Listener (die virtuelle Kamera, bzw. wir die vor dem Schirm sitzen) und eine Source „der Emitter“.

Machen wir zuerste mal die Source:

  • AL_BUFFER ist der Puffer den wir an unsere Source gebunden haben
  • AL_PITCH ist wie der Name schon sagt der Pitchwert Werte kleiner als 1.0 hören sich sehr Doomig an ;-)
  • AL_GAIN ist die Lautstärke
  • AL_POSITION ist wie der Name schon sagt die Position im 3D Raum (ich habe das im Beispielprojekt als Vektor abgebildet)
  • AL_VELOCITY die Geschwindigkeit (weil sich die Source ja im Raum bewegen kann)
  • AL_LOOPING dürfte klar sein

Der Listener

 alListenerfv(AL_POSITION,    ListenerPos);
 alListenerfv(AL_VELOCITY,    ListenerVel);
 alListenerfv(AL_ORIENTATION, ListenerOri);

  • AL_POSITION und AL_VELOCITY siehe oben
  • AL_ORIENTATION (Ausrichtung) benötigt 6 Werte, wobei die ersten 3 die XYZ Koordinaten sind

die letzten 3 beschreiben den Up-Vektor, (0,1,0) wobei 1 für eine positive Y-Richtung steht (also nach oben zeigend).

Wer jetzt denkt das Abspielen eines Sounds mit NSSound wäre einfach, der wird sich wundern wie einfach es mit OpenAL ist. Ein simples

alSourcePlay(Source);
reicht aus um den Sound abzuspielen. Einfach oder ;-)

Wenn wir fertig sind kommen noch die üblichen Aufräumarbeiten mit

alDeleteBuffers(1, &Buffer);
alDeleteSources(1, &Source);
alutExit();
Das war dann schon alles. Hier das erste Beispielprojekt dazu openal01.zip

Sound bewegen

Im zweiten Teil werden wir den Listener mal im Raum bewegen. Dazu hab ich eine Kamera-Klasse gebastelt, die uns einiges an Arbeit abnimmt. Da ja wie gesagt der Listener unsere virtuelle Kamera ist, müssen beide ja an der gleichen Position im Raum „stehen“.

Zuerst erstellen wir die Kamera mit

_camera = [[MAGCamera alloc]init];
[_camera setViewPort:[_view bounds] foV:45.0f zMin:1.0f zMax:300.0f];
[_camera setPosition: makeVector(0,0,10)];
und setzten sie auf die Position X:0 Y:0 Z:10

der eigentlich interessante Teil steht in der tick-Methode, wie gesagt wir wollen den Listener ja bewegen was dann so aussieht

- (void)tick:(id)sender
{		
[_view clearView];
 
static	float	wobble = 0;
wobble +=  0.01f;			
MAGVector p = makeVector(0.0f, 0.0f, (50.0f + sin(wobble) * 40.0f) );
[_camera setPosition: p];
[_camera animate:1.0f];
 
MAGVector po = [_camera position];	
alListener3f(AL_POSITION, po.x, po.y, po.z);
 
[_view setNeedsDisplay:YES];
}

zuerst löschen wir unser View, danach erstellen wir einen Vektor. Mit der simplen sin Funktion bewegen wir unsere Kamera auf der Z-Achse vor und zurück. Dann holen wir uns die Kameraposition und übergeben sie dem Listener. Zum Schluß zeichnen wir unser Bild und fertig sind wir.

Wenn alles geklappt hat, sollten wir ein rotierendes Dreieck sehen, das sich anscheinend auf uns zu und wieder weg bewegt. Tatsächlich bewegen wir nähmlich die Kamera und nicht das Dreieck.

Ich habe das nur dazu benutzt, um es visuell darzustellen, wie sich der Sound „bewegt“.

Wie ihr vielleicht bemerkt habt, gibts in dem Projekt noch eine MAGVector.h. Ich habe mich absichtlich aus Performancegründen NICHT dafür entschieden eine Klasse daraus zu basteln, sondern das Ganze in simple C-Funktionen zu kapseln, da wir später sehr viel mit Vektoren rumhantieren werden.

openal02.zip

Mehrere Sounds laden und verwalten

So, im dritten und letzten Teil, will ich noch kurz zeigen wie man mehrere Sounds gleichzeitig abspielt. Um das Ganze übersichtlicher zu halten, habe ich eie Klasse „SoundObject“ angelegt. Die Klasse hat 2 Methoden die das Laden und Abspielen der Sounds managed

-(BOOL)loadSound:(NSString*)filename ofType:(NSString*)type;
-(void)playSound:(BOOL)looped;

Desweiteren noch einige Setter und Getter Methoden, die alle selbsterklärend sind.

Kurz zum DemoProjekt. Es werden 3 unterschiedliche Sounds geladen (Schüsse) Beim Start des Programms sind 3 Zielscheiben auf dem Bildschirm zu sehen, diese 3 können nun mit den Tasten 1,2,3 „beschossen“ werden.

Wobei bei einem Schuß auf die linke Scheibe der Sound auch aus dem linken Lautsprecher kommt. Der mittlere Schuß aus beiden und entsprechend der rechte Schuß aus dem rechten Lautsprecher. Das haben wir durch die „Positionierung“ mit

[_gun1 setPosition:makeVector(-2.0f, 0.0f, 0.0f)];
gemacht, was hier bedeutet:

  • verschiebe auf der X-Achse 2 Einheiten nach links
  • 0 Einheiten auf der Y-Achse und
  • 0 Einheiten auf der Z-Achse.

Hier bietet es sich nun an, ähnlich wie bei unserem TextureManager aus SpaceInvaders einen Manager (ich denke ein Singleton macht da am meisten Sinn) zu schreiben, der sich um die Verwaltung der Sounds kümmert.

openal03.zip

So, soweit erst mal zu OpenAL, ich denke das war nicht schwierig zu verstehen.

Ich wünsch euch viel Spaß beim probieren. Im nächsten Teil, werde ich einen Partikel-Editor schreiben, den wir für unser zweites Spiel benötigen (dann gibts endlich richtig 3D ;-).

Für Anregungen oder Sonstiges freue ich mich immer, vielleicht hat jemand ne Idee für weitere Wikis zum Thema.

Viel Spaß

wolf_10de

 
wiki/openal.txt · Zuletzt geändert: 2007/12/28 12:10 (Externe Bearbeitung)
 
Falls nicht anders bezeichnet ist der Inhalt dieses Wikis unter der folgenden Lizenz veröffentlicht:CC Attribution-Noncommercial-Share Alike 3.0 Unported
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki