OpenAL в Delphi: часть первая, введение
Автор: Zakus
Предисловие
Здравствуйте дорогие мои обитатели Дельфинария.
Сегодня мы подробно поговорим о библиотеке OpenAL
и о том, как её использовать в проектах на Delphi под платформу Win32.
Что такое OpenAL?
OpenAL это кросс-платформенная библиотека для работы с 3D звуком. Её задачи: эффективная работа
с аудио оборудованием, вывод звука, а также создания эффекта трёхмерного пространства.
Если вы сомневаетесь, стоит ли использовать эту библиотеку в своих играх, посмотрите на официальном
сайте OpenAL, список приложений, использующих эту
библиотеку.
Там вы можете увидеть много известных названий, таких как Doom3, Quake4 и др.
Как оно выглядит и где взять?
Для работы программ, использующих OpenAL, у вас в системе должен присутствовать файл OpenAL32.dll.
Если его нет – вы можете скачать всё необходимое тут,
там же можно скачать OpenAL SDK.
Хотя примеры и документация из SDK рассчитаны на Си программистов, принципы работы с OpenAL везде одинаковые
(как собственно почти все названия функций), так что оно вам пригодится.
Основные принципы
В OpenAL есть три основных понятия – буферы, источники и слушатель.
* Буферы – это структуры, которые содержат в себе сам звук в несжатом виде, а также некоторую вспомогательную информацию.
* Источники - это структуры, которые как бы олицетворяют звуки в нашем 3D пространстве. Каждый источник можно привязать к
определённому буферу, собственно от этого и зависит какой звук представляет источник. Источник также содержит в себе
информацию о положении в пространстве (x,y,z), громкости, скорости воспроизведения, текущей скорости и направление
движения (эти данные используются для имитации эффекта Доплера), текущем статусе (воспроизводиться ли в данный момент, зацикливать воспроизведение) и др.
* Слушатель (может быть только один на контекст воспроизведения, о контексте чуть ниже) - тоже структура, которая хранит в себе информацию о позиции слушателя в пространстве, уровне его слуха, его скорости и т.д.
OpenAL + Delphi
Итак приступим.
Для начала нам нужен модуль, в котором были бы описаны все типы, константы, а также привязанные к dll-файлу прототипы
функций и процедур OpenAL. Чтобы компилятор знал, откуда вызывать сами функции, а чудесная среда Delphi могла нам
выдавать удобные подсказки. Этот файл конечно можно написать самому, для разминки,
но если вам и без того есть что делать, то можно взять его у добрых людей - http://www.noeska.com/doal/downloads.aspx,
которые этот файл уже написали за нас.
Скачанный файл (OpenAL.pas) разместите в той же папке где и *.dpr файл вашей программы
(в которой вы хотите использовать OpenAL), или же в папке lib директории Delphi.
После чего подключите модуль OpenAL к своему проекту, записав в разделе uses имя модуля.
Поздравляю, теперь мы можем вызывать функции и использовать константы и типы OpenAL в своей программе.
Перед тем как начать писать, давайте разберём схему работы OpenAL:
1) Сначала мы должны получить доступ к устройству воспроизведения: а именно выбрать с каким аудио устройством будем
работать
2) Далее мы создаём контекст воспроизведения (здесь есть определённое сходство с OpenGL =) и делаем его текущим
3) Устанавливаем параметры слушателя
4) Далее во время выполнения программы в нужные нам моменты создаём буферы, источники и производим с ними нужные нам манипуляции
5) Закончив свои грязные дела… убираем за собой… ну там освобождаем контекст и всё такое.
Теперь ближе к телу. Не будем отвлекаться на VCL или WinAPI - делаем консольное приложение.
program OpenALDelphiDemo; {$APPTYPE CONSOLE} uses OpenAL; //подключённый модуль с http://www.noeska.com/doal/ var MainDevice: TALCdevice; //переменная которая отвечает за устройство воспроизведения MainContext: TALCcontext; //переменная отвечающая за контекст FirstBuffer: TALuint; //через эту переменную будем получать доступ к буферу FirstSource: TALuint; //а через эту – к источнику // если нужно несколько буферов/источников, лучше всего //сделать массивы буферов/источников //Процедуры, которые мы будем использовать // для установки позиции источников (и т.п.) //хотят в качестве аргументов, массивы из трёх элементов типа TALfloat //поэтому определяем такие переменные sourcepos: array [0..2] of TALfloat= ( 0.0, 0.0, 0.0 ); //позиция источника sourcevel: array [0..2] of TALfloat= ( 0.0, 0.0, 0.0 ); //движение источника // 5 переменных ниже нужны будут нам для загрузки звука в буфер format: TALenum; data: TALvoid; size: TALsizei; freq: TALsizei; loop: TALint; //та же история что и с источником, X,Y,Z в виде массива… listenerpos: array [0..2] of TALfloat= ( 0.0, 0.0, 0.0); //позиция listenervel: array [0..2] of TALfloat= ( 0.0, 0.0, 0.0); //движение listenerori: array [0..5] of TALfloat= ( 0.0, 0.0, -1.0, 0.0, 1.0, 0.0); //ориентация begin InitOpenAL; //инициализируем OpenAL MainDevice := alcOpenDevice(nil); //получаем доступ к устройству, nil – означает что мы //берём первое удобное устройство в системе MainContext := alcCreateContext(MainDevice,nil); //получаем контекст для нашего //устройства, второй параметр - ссылка //атрибуты устройства, пока что не //трогаем, ставим nil alcMakeContextCurrent(MainContext); //делаем контекст текущим alGenBuffers(1, @FirstBuffer); //просим выделить нам один буфер и вернуть на него //указатель в FirstBuffer alutLoadWAVFile('TestSound.wav',format,data,size,freq,loop); //функция загружает данные //из wav-файла в память… alBufferData(FirstBuffer,format,data,size,freq); //переносим загружённые данные в //выделенный ранее буфер alutUnloadWAV(format,data,size,freq); //выгружаем звук alGenSources(1,@FirstSource); // просим выделить нам один источник //функции alSourcei, alSourcefv работают следующим способом, первый аргумент – //источник, у которого мы будем что-то изменять, второй – параметр источника, который //мы будем изменять, третий - новое значения для изменяемого параметра alSourcei ( FirstSource, AL_BUFFER, FirstBuffer); //связываем наш источник с буфером alSourcefv ( FirstSource, AL_POSITION, @sourcepos); //устанавливаем позицию alSourcefv ( FirstSource, AL_VELOCITY, @sourcevel); //устанавливаем движение alSourcei ( FirstSource, AL_LOOPING, AL_TRUE); //просим чтобы источник //воспроизводил данные из буфера - по кругу //устанавливаем параметры слушателя, всё также как и с источниками, только указывать //слушателя не нужно, так как он у нас один alListenerfv(AL_POSITION,@listenerPos); //позиция alListenerfv(AL_VELOCITY,@listenerVel); //движение alListenerfv(AL_ORIENTATION,@listenerOri); // ориентация alSourcePlay(FirstSource); //функция просит источник FirstSource воспроизводить звук) readln; // делаем паузу пока кто нить не нажмёт [ENTER] //освобождаем устройство, контекст, и т.д. и т.п. alcMakeContextCurrent(nil); alcDestroyContext(MainContext); alcCloseDevice(MainDevice); end. |
Положите в директорию к такой программе файл "TestSound.wav" и программа будет его воспроизводить.
Все эти типы переменных, что вы видите в листинге, описаны в модуле OpenAL.pas.
Имена типов практически такие же как и в OpenAL SDK (за исключением буквы Т в начале имён:
это чисто дельфийский прикол, eсли хотите, чтобы всё было полностью по спецификации то можете
изменить типы в модуле, это не трудно).
Для того, что бы перемещать источник по сцене, используйте в нужный вам момент
процедуру alSourcefv(Source, AL_POSITION, @sourcepos). Аргумент AL_POSITION – говорит
о том, что вы хотели бы изменить позицию. @sourcepos – уже знакомый вам массив из трёх
элементов, это новые координаты размещения источника.
Примечания:
* В связи с тем, что alut-библиотека почему-то отсутствует в виде dll-файла (есть только lib-файл для MSVC++),
в данной ситуации функции alut* реализованы на объектном паскале в модуле OpenAL.pas.
* Для того чтобы звук позиционировался в пространстве, он должен быть монофоническим.
Если же звук стереофонический, то он всегда будет находиться в одной позиции со слушателем,
это связано с тем, что в трёхмерном пространстве отсутствует такое понятие как стерео/моно.
Если я что-то забыл – ну извиняйте.
Задавайте вопросы на форуме - постараюсь ответить.
На сегодня всё. В следующий раз будем разбираться с загрузкой mp3, ogg, и кое-чем ещё…
15 декабря 2005
Обновление: 18 декабря 2005
