Wie soll ich OpenAL-Puffer entbinden und löschen?

12

Ich benutze OpenAL, um Sounds abzuspielen. Ich versuche, eine Fire-and-Forget-Play-Funktion zu implementieren, die eine Puffer-ID verwendet und einer Quelle aus einem Pool zuweist, den ich zuvor zugewiesen habe, und sie wiedergibt. Es gibt jedoch ein Problem mit der Objektlebensdauer.

In OpenGL lösen Löschfunktionen entweder automatisch die Bindung von Objekten (z. B. Texturen) oder löschen das Objekt automatisch, wenn es schließlich nicht mehr gebunden ist (z. B. Shader), und daher ist das Löschen in der Regel einfach zu verwalten. Schlägt jedoch alDeleteBuffersstattdessen einfach fehl, AL_INVALID_OPERATIONwenn der Puffer noch an eine Quelle gebunden ist.

Gibt es eine idiomatische Methode zum "Löschen" von OpenAL-Puffern, die es ihnen ermöglicht, das Abspielen zu beenden und dann automatisch die Bindung zu lösen und sie wirklich zu löschen? Muss ich die Pufferverwaltung tiefer in den Quellpool einbinden (z. B. erfordert das Löschen eines Puffers auch das Überprüfen aller zugewiesenen Quellen)?

Gibt es in ähnlicher Weise eine idiomatische Möglichkeit, Puffer nach Beendigung des Spiels zu lösen (aber nicht zu löschen)? Es wäre schön, wenn ich auf der Suche nach einer freien Quelle nur sehen müsste, ob überhaupt ein Puffer angeschlossen ist, und nicht den Quellstatus überprüfen müsste.

(Ich verwende C ++, obwohl Ansätze für C auch in Ordnung sind. Ansätze, die eine GCd-Sprache voraussetzen und Finalizer verwenden, sind wahrscheinlich nicht anwendbar.)


quelle
Wenn Sie noch eine Antwort benötigen, habe ich eine Garbage Collection-Methode in der Gorgon-Engine verwendet: sf.net/p/gorgon-ge
Cem Kalyoncu

Antworten:

8

Vor dem Löschen eines Puffers müssen Sie die Bindung zu jeder Quelle aufheben, die ihn verwendet (z. B .: alSourcei(mSourceId, AL_BUFFER, NULL);oder alle Quellen löschen, die an den Puffer gebunden sind.

Sie müssen die Länge jedes Ihrer Sounds verfolgen, um sie nach Abschluss freizugeben. Sie können dies mithilfe einer Struktur für jede Quelle tun, um die Klanglänge und die gespielte Zeit beizubehalten (aktualisiert bei jedem Spiel-Tick). Ex:

struct AudioVoice
{
    ALuint          mSourceId;
    ALuint          mMsDuration;
    ALuint          mMsPlayed;
};

Wenn Sie ein komponentenbasiertes System verwenden, können Sie regelmäßig alle laufenden Quellen auf Vollständigkeit prüfen und dort das Aufheben der Bindung / das Löschen der Quelle vornehmen.

Wenn Sie die Wiedergabe- / Pausenänderungen in Ihrem Code nicht nachverfolgen, sollten Sie auch prüfen, ob die Quellen wiedergegeben werden, bevor Sie die Wiedergabezeit erhöhen.

ALint sourceState;
alGetSourcei(mSourceId, AL_SOURCE_STATE, &sourceState);
if (sourceState == AL_PLAYING) { /* increase played time */  }

Wenn Sie die an einen Puffer gebundenen Quellen verfolgen möchten, können Sie eine Struktur mit der ID Ihres Puffers und einen Vektor verwenden, der mit den Quellstrukturen verknüpft ist. Auf diese Weise können Sie sogar alle Quellen unterbrechen, die an einen Puffer gebunden sind, den Sie freigeben möchten SO SCHNELL WIE MÖGLICH. Ex:

struct AudioData
{
    RKuint                      mMsDuration;
    ALuint                      mSourceId;
    std::vector<AudioVoice*>    mVoices;
};

Dies sollte ausreichen, um Sie auf den richtigen Weg zu bringen. Ich kann Ihnen keinen detaillierteren Code aus meinen Projekten geben, da diese stark von Makros und handgemachten RTTI-Mechanismen abhängen.

Kojote
quelle