OpenAL 1.1, расширение EFX, поддержка фильтров и эффектов

На сайте developer.creative.com можно скачать OpenAL 1.1 SDK (к сожалению пока нет соответствующей версии для Linux).

Версия 1.1 добавила в OpenAL целый ряд новых полезных и удобных возможностей, которых с избытком хватает для оправдания перехода на нее.

Основные отличия от версии 1.0

Одним из отличий версии 1.1 стало добавление API, предназначенного для записи звука (Recording API).

Добавлена также возможность позиционирования внутри источника звука (по времени или по сэмплам).

Фактически упразднена библиотека ALUT, вместо нее в SDK предложена другая библиотека, на основе которой и сделаны все примеры из SDK.

Было проведено уточнение документации, добавлено несколько новых моделей учета расстояния до источника звука, добавлены новые типы данных ALchar и ALCchar.

Теперь функция alcCloseDevice возвращает значение типа ALCboolean для обозначения успешности операции.

Однако наиболее интересной возможностью стала поддержка звуковых фильтров и эффектов при помощи расширения ALC_EXT_EFX.

Поддержка записи звука

Помимо устройств, служащих для воспроизведения звука, OpenAL 1.1 также может предоставлять возможность для записи звука (через устройства для записи звука - capture devices).

Устройства для записи звука функционируют независимо от остальной части библиотеки, не содержат контекст и не обладают каким-либо состоянием.

Для подключения к устройству записи звука служит функция akcCaptureOpenDevice. Для получения полного списка всех доступных устройств для записи звука следует использовать функцию alcGetString с параметром ALC_CAPTURE_DEVICE_SPECIFIER передав NULL в качестве параметра device.

char * captureDevices = (char *) alcGetString ( NULL, ALC_CAPTURE_DEVICE_SPECIFIER );
		
if ( captureDevices == NULL )
    printf ( "No capture devices found\n" );
else
    printf ( "Capture devices: %s", captureDevices );

Функция alcCaptureOpenDevice описывается следующим образом:

ALCdeviec * alcCaptureOpenDevice ( const ALCchar * deviceName, ALCuint freq, ALCenum format, ALCsizei bufferSize );

Параметр deviceName задает имя требуемого устройства, вместо этого имени можно передать значение NULL для получения устройства по умолчанию.

Параметры freq и format задают формат, в котором звуковые данные будут предоставляться приложению и могут принимать значения, допустимые в функции alBufferData.

Параметр bufferSize задает количество сэмплов, хранимых во внутреннем буфере OpenAL. Реализация OpenAL может на самом деле использовать буфер большего размера.

Если функция alcCaptureOpenDevice возвращает значение NULL, то это говорит об отсутствии подходящих устройств для записи звука или об отсутствии поддержки требуемого формата.

Для "закрытия" (отключения) устройства для записи звука служит следующая функция:

ALCboolean alcCaptureCloseDevice ( ALCdevice * device );

В зависимости от успешности операции будет возвращено значение ALC_TRUE или ALC_FALSE.

После открытия устройства для записи звука можно использовать функции alcCaptureStart и alcCaptureStop (для включения и приостановки записи звука):

void alcCaptureStart ( ALCdevice * device );
void alcCaptureStop  ( ALCdevice * device );

После начала записи звуковые данные в выбранном формате будут записываться в кольцевой буфер, размер которого был задан в функции alcCaptureOpenDevice при открытии устройства.

При помощи функции alcGetInteger с параметром ALC_CAPTURE_SAMPLES можно получить количество доступных сэмплов в буфере.

Для чтения сэмплов из внутреннего буфера OpenAL в предоставляемый пользователем буфер служит функция alcCaptureSamples:

void alcCaptureSamples ( ALCdevice * device, ALCvoid * buf, ALCsizei samples );

Расширение ALC_EXT_EFX и работа с ним

Данное расширение добавляет в OpenAL поддержку звуковых фильтров и эффектов для выводимого звука. Аккуратное использование данного расширения позволяет радикально изменить звуковой мир вашего приложения/игры.

На следующем рисунке приведена типичная архитектура для OpenAL 1.0.

OpenAL 1.0 architecture

Рис 1. Архитектура OpenAL без фильтров и эффектов.

Расширение ALC_EXT_EXF вводит новую архитектуру для обработки звука в OpenAL, изображенную на рис. 2.

OpenAL 1.1 architecture

Рис 2. Архитектура OpenAL с фильтрами и эффектами.

Как видно к любому источнику звука можно добавить непосредственный (direct) фильтр (обычно используется low-pass или high-pass фильтры, т.е. фильтры образующие высокие или низкие частоты). Звук, после прохождения через непосредственный фильтр сразу же направляется к выходному миксеру.

Кроме этого появилась возможность для источников звука посылать данные (при необходимости с обработкой их фильтром) на дополнительные каналы выхода (slots). К каждому такому каналу можно подключить определенный звуковой эффект, преобразующий звуковые данные, которые после него также поступают на выходной миксер.

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

В реальной жизни подобные эффекты окружения получаются за счет многократного отражения и поглощения (а также рассеивания) звука стенами (а также полом и потолком) помещения.

Так если источник звука находится внутри помещения, то будет происходить многочисленные переотражения звука от стен, поля и потолка.

При этом как размер помещения, так и материал, из которого изготовлены его стены, пол и потолок, будут оказывать сильное влияние на то как воспринимается слушателем итоговый звук.

По замыслу разработчиков OpenAL каждый эффект соответствует определенному помещению (environment), а используемые фильтры позволяют более точно учитывать особенности распространения и отражения звука.

Различные звуковые карты поддерживают как различное число одновременно работающих эффектов, так и разные типы эффектов.

Для задания схемы обработки звука, аналогичной представленной на рис. 2., расширение ALC_EXT_EFX вводит ряд новых функций и констант. Подробнее обо всех них можно прочесть в содержащейся в OpenAL SDK документации, мы же сейчас сразу перейдем к рассмотрению набора классов, упрощающих работу с фильтрами и эффектами. Весь соответствующий исходный код доступен по ссылке в конце статьи.

За основу этих классов были взяты классы из первой статьи по OpenAL, с небольшими изменениями и добавленной новой функциональностью.

На следующем рисунке приведена UML-диаграмма классов.

classes diagram

Рис 3. Диаграмма классов для работы с OpenAL 1.1.

Как видно из приведенной диаграммы каждый фильтр представлен объектов класса OpenAlFilter (или класса, унаследованного от него). При этом сам класс OpenAlFilter является лишь общей оберткой и от него наследуются классы для конкретных фильтров (см. рис 4.).

Рис 4. Классы фильтров.

Для подключения непосредственного фильтра к источнику звука (результат применения фильтра будет непосредственно направляться в выходной миксер) у класса SoundSource служит метод attachFilter.

bool attachFilter ( OpenAlFilter * filter );
bool detachFilter ();

При помощи метода detachFilter от источника звука отсоединяется непосредственный фильтр.

OpenAlContext	context;
SoundData     * data = OpenAlContext :: open ( "wavdata/footsteps.wav" );

if ( data == NULL )
    return 1;

bool		   attached = true;
SoundSource  * sound    = new SoundSource ( data, true );
OpenAlFilter * filter   = new OpenAlLowPassFilter ( 1.0, 0.1 );

if ( !filter -> isOk () )
    printf ( "Filter failure\n" );

if ( !sound -> attachFilter ( filter ) )
    printf ( "Error attaching filter\n" );

printf ( "Filter: %s\n", attached ? "on" : "off" );

sound -> play ();

for ( ; ; )
{
    sound -> update ();

    if ( kbhit () )
    {
        int ch = getche ();

        if ( ch == 27 )
            break;

        attached = !attached;

        if ( attached )
            sound -> attachFilter ( filter );
        else
            sound -> detachFilter ();

        printf ( "Filter: %s\n", attached ? "on" : "off" );
    }
                                        // make some delay
    int i, j;

    for ( i = j = 0; i < 1000; i++ )
        j += i*j + 1;	    
}

Подключение эффектов несколько сложнее, поскольку на вход одного эффекта могут поступать данные сразу от нескольких источников, причем для каждого источника может использоваться специальный фильтр. Возможна также ситуация, когда от одного источника поступают данные, прошедшие разные фильтры.

Поэтому следует использовать объект класса OpenAlSlot, представляющий собой место (слот) куда будут направляться данные с различных источников. При этом одни источник может направлять данные сразу в несколько слотов, при необходимости используя при этом различные фильтры.

Точно также один слот может принимать данные сразу от нескольких источников звука.

Методы attacthEffect и detachEffect класса OpenAlSlot позволяют подсоединять и отсоединять эффекты к/от отдельным слотам.

Для того, чтобы направить данные (иле же перестать направлять туда данные) от заданного источника звука в заданный слот служит метод enableAuxSlot (disableAuxSlot) класса SoundSource:

bool enableAuxSlot  ( OpenAlSlot   * slot, OpenAlFilter * filter = NULL );
bool disableAuxSlot ( OpenAlSlot   * slot );

Класс OpenAlEffect является общей оберткой для произвольного эффекта, конкретные эффекты должны реализовываться как его подклассы, предоставляя удобный интерфейс для настройки параметров конкретного эффекта.

В прилагаемом к статье исходном коде содержится только один подобный класса - ReverbEffect, поскольку у меня ни на одном компьютере другие эффекты к сожалению просто не поддерживаются :(((

Ниже приводится пример использования данных классов для воспроизведения звука с подключением эффекта.

OpenAlContext context;
ALuint        type = AL_EFFECT_REVERB;
SoundData   * data = OpenAlContext :: open ( "wavdata/footsteps.wav" );
	
if ( data == NULL )
	return 1;
		
bool          attached = true;
SoundSource * sound = new SoundSource ( data, true );
OpenAlEffect  effect ( type );
OpenAlSlot    slot;

if ( !effect.isOk () )
    printf ( "Effect failure !\n" );
		
slot.attachEffect ( &effect );
sound -> enableAuxSlot ( &slot );
sound -> play          ();

printf ( "Effect: %s\n", attached ? "on" : "off" );

for ( ; ; )
{
    sound -> update ();

    if ( kbhit () )
    {
        int ch = getche ();

       if ( ch == 27 )
           break;

        attached = !attached;

        if ( attached )
            sound -> enableAuxSlot  ( &slot );
        else
            sound -> disableAuxSlot ( &slot );

        printf ( "Effect: %s\n", attached ? "on" : "off" );
    }

                                             // make some delay
    int i, j;

   for ( i = j = 0; i < 1000; i++ )
       j += i*j + 1;	    
}
	

Весь исходный код к данной статье можно скачать здесь, откомпилированные программы для M$ Windows также доступны.

Обратите внимание, что для компилирование примеров к этой статье Вам кроме OpenAL 1.1 SKD также понадобятся следующие библиотеки - libmad, Ogg Vorbis и Ogg Bitstream.

Valid HTML 4.01 Transitional

Напиши мне
Используются технологии uCoz