Jak usunąć powiązanie i usunąć bufory OpenAL?

12

Używam OpenAL do odtwarzania dźwięków. Usiłuję zaimplementować funkcję odtwarzania typu „podpal i zapomnij”, która pobiera identyfikator bufora i przypisuje go do źródła z puli, którą wcześniej przydzieliłem, i odtwarza go. Występuje jednak problem z czasem życia obiektu.

W OpenGL funkcje usuwania albo automatycznie usuwają powiązanie rzeczy (np. Tekstury), albo automatycznie usuwają rzecz, gdy w końcu jest niezwiązana (np. Shadery), więc zazwyczaj łatwo jest zarządzać usuwaniem. Jednak alDeleteBufferszamiast tego po prostu się nie powiedzie, AL_INVALID_OPERATIONjeśli bufor jest nadal powiązany ze źródłem.

Czy istnieje idiomatyczny sposób na „usunięcie” buforów OpenAL, który pozwala im zakończyć grę, a następnie automatycznie odłączyć i naprawdę je? Czy muszę głębiej powiązać zarządzanie buforami z pulą źródłową (np. Usunięcie bufora wymaga również sprawdzenia wszystkich przydzielonych źródeł)?

Podobnie, czy istnieje idiomatyczny sposób na usunięcie powiązania (ale nie usunięcie) buforów po zakończeniu gry? Byłoby miło, gdyby szukałem darmowego źródła, musiałem tylko sprawdzić, czy bufor jest w ogóle podłączony i nie zawracać sobie głowy sprawdzaniem stanu źródła.

(Używam C ++, chociaż podejścia do C również są w porządku. Podejścia zakładające język GCd i używanie finalizatorów prawdopodobnie nie mają zastosowania).


źródło
Jeśli nadal potrzebujesz odpowiedzi, użyłem metody wyrzucania elementów bezużytecznych w silniku Gorgon: sf.net/p/gorgon-ge
Cem Kalyoncu 28.12. O

Odpowiedzi:

8

Przed usunięciem bufora należy usunąć powiązanie z każdym źródłem, które go używa (np .: alSourcei(mSourceId, AL_BUFFER, NULL);lub usunąć wszystkie źródła powiązane z buforem.

Musisz śledzić długość każdego z dźwięków, aby zwolnić je po zakończeniu. Możesz to zrobić za pomocą struktury dla każdego źródła, aby zachować długość dźwięku i odtwarzany czas (aktualizowany przy każdej grze). Dawny:

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

Jeśli używasz systemu opartego na komponentach, możesz okresowo sprawdzać, czy wszystkie uruchomione źródła są ukończone, i usuwać tam powiązanie / usunięcie źródła.

Jeśli nie śledzisz zmian odtwarzania / pauzy w kodzie, będziesz również chciał sprawdzić, czy odtwarzane są źródła przed wydłużeniem czasu odtwarzania.

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

Jeśli chcesz śledzić źródła powiązane z buforem, możesz użyć struktury o identyfikatorze bufora i wektorze łączącym się ze strukturami źródłowymi, w ten sposób możesz nawet przerwać wszystkie źródła powiązane z buforem, który musisz zwolnić JAK NAJSZYBCIEJ. Dawny:

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

To powinno wystarczyć, abyś znalazł się na właściwej drodze. Nie mogę podać bardziej szczegółowego kodu z moich projektów, ponieważ w dużej mierze opierają się one na makrach i ręcznie wykonanych mechanizmach RTTI.

Kojot
źródło