Как мне отсоединить и удалить буферы OpenAL?


12

Я использую OpenAL для воспроизведения звуков. Я пытаюсь реализовать функцию воспроизведения «забей и забудь», которая берет идентификатор буфера и назначает его источнику из пула, который я ранее выделил, и воспроизводит его. Однако существует проблема с временем жизни объекта.

В OpenGL функции удаления либо автоматически связывают вещи (например, текстуры), либо автоматически удаляют вещь, когда она в конце концов не связана (например, шейдеры), и поэтому обычно легко управлять удалением. Однако alDeleteBuffersвместо этого просто происходит сбой, AL_INVALID_OPERATIONесли буфер все еще связан с источником.

Есть ли идиоматический способ «удалить» буферы OpenAL, который позволяет им закончить игру, а затем автоматически отменяет привязку и действительно их? Нужно ли более тесно связать управление буфером с пулом источников (например, удаление буфера требует проверки всех выделенных источников)?

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

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

openal 

Если вам все еще нужен ответ, я использовал метод сбора мусора в движке Gorgon: 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.