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
Dies erzeugt ein Handle am StandardDevice, was soviel bedeutet wie, wir initialisieren die Standard Soundschnittstelle.
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:
Der Listener
alListenerfv(AL_POSITION, ListenerPos); alListenerfv(AL_VELOCITY, ListenerVel); alListenerfv(AL_ORIENTATION, ListenerOri);
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
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.
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:
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.
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