Дельфинарий (Delphi, FreePascal)
GameDev.ru / Сообщества / Дельфинарий / Статьи / OpenAL в Delphi: часть первая, введение

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

Категории: Delphi, OpenAL


Обновление: 18 декабря 2005

2001—2014 © GameDev.ru — Разработка игр