Як слід від’єднати та видалити буфери OpenAL?


12

Я використовую OpenAL для відтворення звуків. Я намагаюся реалізувати функцію відтворення вогню і забути, яка бере ідентифікатор буфера і призначає його джерелу з пулу, який я раніше виділив, і відтворює його. Однак існує проблема з життям об'єкта.

У OpenGL функції видалення або автоматично від’єднує речі (наприклад, текстури), або автоматично видаляє річ, коли вона в кінцевому підсумку не пов'язана (наприклад, шейдери), і таким чином, як правило, легко управляти видаленням. Однак alDeleteBuffersнатомість просто не вдається, AL_INVALID_OPERATIONякщо буфер все ще пов'язаний з джерелом.

Чи є ідіоматичний спосіб "видалити" буфери OpenAL, що дозволяє їм закінчити гру, а потім автоматично від'єднати і справді їх? Чи потрібно мені більш глибоко прив’язувати управління буфером до пулу джерел (наприклад, для видалення буфера потрібно також перевірити всі виділені джерела)?

Аналогічно, чи існує ідіоматичний спосіб від’єднати (але не видалити) буфери, коли вони закінчують програвати? Було б непогано, якби я шукав вільне джерело, мені потрібно було лише перевірити, чи буфер взагалі приєднаний і чи не турбує перевірку стану джерела.

(Я використовую C ++, хоча підходи для C також чудові. Підходи, що передбачають мову GCd та використання фіналізаторів, ймовірно, не застосовуються.)

openal 

Якщо вам ще потрібна відповідь, я використав метод збору сміття в двигуні Горгона: sf.net/p/gorgon-ge
Cem Kalyoncu

Відповіді:


8

Перед видаленням буфера необхідно від’єднати його від кожного джерела, який використовує його (наприклад: alSourcei(mSourceId, AL_BUFFER, NULL);або видалити всі джерела, пов'язані з буфером).

Вам потрібно стежити за довжиною кожного з ваших звуків, щоб випустити їх після завершення. Це можна зробити, використовуючи структуру для кожного джерела, щоб зберегти тривалість звуку та час відтворення (оновлено галочку кожної гри). Наприклад:

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

Якщо ви використовуєте систему, що базується на компонентах, ви можете періодично перевіряти всі запущені джерела на завершення і виконувати видалення / видалення джерела там.

Якщо ви не стежите за змінами відтворення / паузи у коді, вам також потрібно перевірити, чи відтворюються джерела, перш ніж збільшити час відтворення.

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

Якщо ви хочете відслідковувати джерела, пов'язані з буфером, ви можете використовувати структуру з ідентифікатором вашого буфера та вектором, що посилається на структуру джерела таким чином, ви навіть можете перервати всі джерела, які пов'язані з буфером, який потрібно випустити ЯКНАЙШВИДШЕ. Наприклад:

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

Цього має бути достатньо, щоб ви потрапили на правильний шлях. Я не можу дати вам більш детальний код з моїх проектів, оскільки вони сильно покладаються на макроси та ручні механізми RTTI.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.