Музыкальные форматы в играх. Разбор форматов: звук в некоторых играх на Unreal Engine

Речь пойдёт о программной библиотеке для работы со звуком, известной под названием FMOD. Разработчиком этого программного продукта является компания Firelight Technologies Pty, Ltd. На момент написания статьи последним релизом FMOD была версия 3.74. С текущим состоянием дел и с новыми версиями, если они появились, вы можете ознакомиться на сайте www.FMOD.org . На том же сайте вы можете получить версии FMOD для различных операционных систем. Прямые ссылки на дистрибутив FMOD расположены

Библиотека функций FMOD представляет собой реализацию API верхнего уровня, который включает широкий набор функций для работы со звуковыми файлами различных форматов, обработки звуковых данных и воспроизведения звука через аудиосистему компьютера или игровых приставок. Для того чтобы рассказать обо всех возможностях этого API потребуется не один десяток web-страниц. Кроме того, основной нашей тематикой названа разработка звуковых игр, для которых главный интерес представляют функции для работы с объёмным (3D) звуком. Знакомством с этими функциями мы и ограничимся. Следует иметь в виду, что данная публикация не является полным руководством по FMOD, поэтому, разбирая приводимые ниже примеры, не следует пренебрегать официальной документацией. Все примеры в статье составлены на языке программирования C (Си).

Для создания источников 3D звука и расчета трёхмерной звуковой картины FMOD (версия для Windows) использует в качестве базы любую из следующих звуковых систем: WMM (Windows Multimedia), DirectSound3D (звуковая подсистема Microsoft DirectX) и A3D. FMOD обеспечивает такое взаимодействие с этими звуковыми системами, что переход от одной из них к другой требует минимальных изменений в коде программы (а часто вообще не требует никаких изменений). При работе с базовой звуковой системой DirectSound3D функции FMOD заметно облегчают управление объёмными источниками звука, упрощают их инициализацию, воспроизведение и позиционирование. Простота программирования FMOD (в сравнении с программированием базовых звуковых систем) является важным достоинством этого API (О программировании непосредственно DirectSound3D можно прочитать в статье Программирование объёмного звука в DirectSound3D).

Другим достоинством FMOD является лёгкость установки - достаточно разместить в системной папке или в папке, из которой запускается приложение, dll библиотеку, чтобы функции FMOD стали доступны. В версии 3.74, кроме обычной для Windows 32-разрядной dll, поставляется 64-разрядная библиотека FMOD.

FMOD содержит подробную документацию и примеры (вместе с заголовочными и другими служебными файлами) для VisualC, BorlandC, Watcom C, Borland Delphi и VisualBasic. Для некоммерческих приложений библиотека FMOD предоставляется бесплатно.

К недостаткам FMOD следует отнести отсутствие таких возможностей (которые реализованы в DirectSound3D), как создание направленных источников звука и создание зависимых источников звука (по крайней мере, в наборе функций FMOD не представлены функции, устанавливающие данные параметры пространственной обработки звука).

Модель пространства в FMOD

Модель пространства (система координат), используемая для размещения источников 3D звука, аналогична модели пространства в DirectSound3D. Здесь используется левосторонняя декартова система координат, состоящая из трёх ортогональных координатных осей. Ось X (икс) направлена вправо; ось Y (игрек) направлена вверх; ось Z (зэт) направлена вперед (то есть в монитор, если сидеть лицом к нему). Расстояние измеряется в метрах, но можно установить другую единицу измерения длин, задав соотношение между метром и новой единицей измерения. Любая точка в пространстве задается своими координатами, которые записываются в последовательности X, Y, Z. Координаты могут принимать как положительные, так и отрицательные значения. Координатную триаду XYZ, характеризующую положение точки в пространстве, можно рассматривать как вектор, начало которого находится в начале отсчета, то есть в точке с координатами (0, 0, 0), и конечной точкой с координатами (X, Y, Z). Кроме векторов положения, в FMOD используются векторы скорости, необходимые для вычисления доплеровского смещения в спектре звука движущихся источников. Вектор скорости задается тремя координатами своей конечной точки (начальной точкой вектора скорости считается точка (0, 0, 0)). Следует заметить, что FMOD (как и DirectSound3D) не занимается расчетом координат движущегося объекта. Эту задачу должен решать программист, передавая функциям FMOD данные, необходимые для моделирования исключительно звуковой картины в конкретной точке пространства и в конкретный момент. То есть по сути FMOD (как и DirectSound3D) рассчитывает статическую звуковую картину, которую программист может сделать динамичной для слушателя (игрока), часто меняя положение источников звука.

В тех функциях FMOD, для которых в качестве параметра должен передаваться вектор, используется указатель на структуру, состоящую из трёх вещественных (float) чисел, или на массив, состоящий из трёх вещественных (float) чисел. То есть две следующие конструкции будут одинаково восприняты функциями FMOD:

/* масив */ float pos = {10.0f, 2.0f, 4.2f}; /* структура */ struct VECTOR { float X; float Y; float Z; }; VECTOR pos = {10.0f, 2.0f, 4.2f};

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

Объекты звуковой картины в FMOD

В FMOD существуют два вида объектов трёхмерного звукового пространства: источники звука и слушатели. В отличие от DirectSound3D, FMOD поддерживает модель нескольких слушателей. Во всем остальном обе системы аналогичны.

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

Функции для работы с 3D звуком

для простоты изложения ниже приводятся не только функции FMOD, отвечающие непосредственно за создание объёмного звука, но и все те функции, которыми необходимо воспользоваться программисту, чтобы работать с библиотекой FMOD. Причем в списке функции расположены в той ориентировочной последовательности, в которой их следует вызывать в программе, взаимодействующей с FMOD. В документации, которая входит в комплект FMOD все приводимые ниже функции помещены в раздел "FSOUND API Reference".

  • FSOUND_GetVersion() - возвращает версию библиотеки FMOD, установленной на компьютере. Возвращаемое значение следует сравнить с константой FMOD_VERSION, которая хранит номер версии FMOD, для которой была скомпилирована программа.
  • FSOUND_SetOutput () / FSOUND_GetOutput () - выбрать/получить базовую звуковую систему (Windows Multimedia, DirectSound, A3D и т.п.). Выбор базовой системы должен производится до вызова функции FSOUND_Init().
  • FSOUND_SetDriver () / FSOUND_GetDriver () - выбрать/получить номер устройства вывода (звуковой карты). Выбор устройства должен производится до вызова функции FSOUND_Init().
  • FSOUND_SetMixer () /FSOUND_GetMixer () - выбрать/получить тип цифрового микшера. Выбор микшера должен производится до вызова функции FSOUND_Init(). Определение типа микшера не является обязательным, так как FMOD самостоятельно определит лучший из имеющихся вариантов.
  • FSOUND_Init() - инициализирует звуковую систему FMOD.
  • FSOUND_Sample_Load () - загружает в память и декодирует звуковой файл (поддерживаются.wav, .mp2, .mp3, .ogg, .raw и др.).
  • FSOUND_3D_SetDistanceFactor () - позволяет установить единицы измерения длин, отличные от метров.
  • FSOUND_3D_SetDopplerFactor () - позволяет установить доплеровское смещение. Базовое значение (1.0) соответствует скорости звука 340 м/с.
  • FSOUND_3D_SetRolloffFactor () - позволяет установить уровень потерь энергии звуковой волны (затухания). Базовое значение (1.0) соответствует нормальным условиям.
  • FSOUND_PlaySoundEx () - проигрывает звуковой файл, загруженный в память, через звуковой канал.
  • FSOUND_3D_SetAttributes () / FSOUND_3D_GetAttributes () - установить/получить вектор положения и вектор скорости источника звука.
  • FSOUND_3D_SetMinMaxDistance () / FSOUND_3D_GetMinMaxDistance () установить / получить минимальное и максимальное расстояние слышимости источника звука. Минимальным называется такое расстояние от источника звука до слушателя, при уменьшении которого громкость звука больше не возрастает, а остается на том значении, которого она достигла на минимальном расстоянии. Устанавливая разные минимальные расстояния, например, для самолета и шмеля, можно сделать их одинаково заметными на слух, несмотря на то, что гул мотора будет восприниматься как более мощный звук. Максимальным называется такое расстояние от источника звука до слушателя, начиная с которого громкость звука больше не уменьшается, а остается на уровне, который она достигла на максимальном расстоянии. Это означает, что как бы далеко не находился источник звука, он будет слышен.
  • FSOUND_SetPaused () - приостанавливает / возобновляет воспроизведение звука в канале.
  • FSOUND_3D_Listener_SetAttributes () / FSOUND_3D_Listener_GetAttributes () - установить/ получить вектор положения, вектор скорости и векторы ориентации слушателя.
  • FSOUND_Update () -обновить состояние звукового микшера, то есть обновить состояние звуковой панорамы, после чего все изменения в положении слушателя или источников звука вступают в силу.
  • FSOUND_Sample_Free () - освобождает память от звуковых данных, загруженных функцией FSOUND_Sample_Load().
  • FSOUND_Close () - выгружает звуковую систему FMOD.

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

Алгоритм использования FMOD в игровых программах

В центре нашего внимания будут игры, использующие объёмный (3D) звук. Как правило, в играх существует основной цикл игры, внутри которого происходит перемещение игровых объектов в пространстве. Такое перемещение может быть вызвано действиями игрока (например, в автосимуляторе это может быть поворот рулевого колеса вправо или влево) или изменением игровой ситуации (например, в "экшене" может приблизится монстр). Рассчитав новые координаты объектов, следует изменить и положение источников звука так, чтобы они соответствовали новому положению объектов в игровом пространстве.

Игровому циклу, как правило, предшествует та часть программы, в которой происходит инициализация переменных, загрузка необходимых библиотек и ресурсов. При использовании FMOD, в этой части должны располагаться функции: FSOUND_SetOutput, FSOUND_SetDriver и FSOUND_SetMixer. В качестве параметра для автоматического определения базовой звуковой системы в функцию FSOUND_SetOutput можно передать -1 (0FFFFFFFFh).

После успешной инициализации FMOD необходимо в соответствии со сценарием игры разместить в памяти звуковые данные. Функция FSOUND_Sample_Load, отвечающая за этот процесс, поддерживает несколько звуковых форматов и загрузка, скажем, .mp3 файла с точки зрения программиста ничем не отличается от загрузки файла в формате wav. Здесь полностью проявляются достоинства библиотеки FMOD, позволяющей упростить утомительную процедуру создания звуковых буферов и загрузки в них данных, характерную для DirectSound. Результатом работы FSOUND_Sample_Load будет указатель на образец звука, размещенный в памяти. Если обратиться к терминологии DirectSound, то это будет аналог вторичного звукового буфера. Указанный образец звука может быть использован для создания нескольких источников 3D звука, при этом нет необходимости создавать дополнительные копии этого образца.

Теперь, когда необходимые данные загружены, можно приступать к формированию трёхмерной звуковой картины. Необходимо помнить, что изменение вектора положения и вектора скорости, а также многих иных характеристик источника звука возможно только непосредственно во время воспроизведения звука функциями FSOUND_PlaySound и FSOUND_PlaySoundEx, поэтому, прежде чем поместить источник звука в какую-либо точку пространства, вы должны начать воспроизведение этого звука. Однако при вызове указанных функций звук будет воспроизводиться в той точке, где находится слушатель (Listener), что может нарушить сцену игры (например, монстр, который должен приближаться из самого дальнего закоулка, вдруг зарычит под ухом у игрока). Чтобы избежать подобного казуса, в функции FSOUND_PlaySoundEx() предусмотрен специальный параметр, который сразу же приостанавливает воспроизведение звука. Молчащий источник можно, без риска нарушить сцену игры, поместить в нужное место и возобновить воспроизведение звука. Для того чтобы изменения в звуковой картине вступили в силу, необходимо вызвать функцию FSOUND_Update.

Следует сказать, что в понятиях FMOD воспроизведение звука происходит через канал (channel), поэтому все, что программист собирается сделать с источником 3D звука, необходимо выполнять, пользуясь функциями, которые работают с каналом. Первым параметром в таких функциях выступает номер канала.

Синтаксис вызова функции FSOUND_PlaySoundEx следующий:

Int F_API FSOUND_PlaySoundEx(int channel, FSOUND_SAMPLE *sptr, FSOUND_DSPUNIT *dspunit, signed char startpaused);

В качестве параметров эта функция получает номер канала (channel), через который будет воспроизводится звук,; указатель (дескриптор sptr) на образец звука, размещенный в памяти; указатель (дескриптор dspunit) на блок каналов, к которому должен присоединиться вновь создаваемый канал (этот параметр может иметь значение NULL); флаг приостановки воспроизведения (paused), который должен быть TRUE, чтобы воспроизведение звука сразу же было приостановлено.

Если необходимо создать новый канал, то в параметре channel передается константа FSOUND_FREE. Если необходимо, чтобы звук воспроизводился во всех существующих каналах, то в channel передается константа FSOUND_ALL.

Функция возвращает номер (дескриптор) канала, через который воспроизводится звук. Если возникла ошибка, то функция возвращает -1 (0FFFFFFFFH). Номер (дескриптор) канала необходим для работы с функциями канального уровня, например, FSOUND_3D_SetAttributes.

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

FSOUND_SAMPLE *samp1 = NULL; int channel1 = -1; /* проверяем версию FMOD */ if (FSOUND_GetVersion()

Следует помнить, что функции FSOUND_PlaySound и FSOUND_PlaySoundEx помещают источник звука в текущую позицию слушателя, поэтому, если в параметре channel этих функций указан номер (дескриптор) существующего канала, то, несмотря на то, что для этого канала функцией FSOUND_3D_SetAttributes была установлена позиция, отличная от позиции слушателя, все равно источник звука переместится в позицию слушателя. Чтобы избежать искажения звуковой картины, необходимо перед вызовом FSOUND_PlaySoundEx сохранить позицию и скорость источника звука в специальных переменных, получив эти значения функцией FSOUND_3D_GetAttributes. После чего вызвать FSOUND_PlaySoundEx с приостановкой воспроизведения; затем переместить источник в нужную точку, воспользовавшись сохраненными значениями, а уж потом продолжить воспроизведение. Указанная последовательность действий, кроме всего прочего, напрямую относится к однократно проигрываемым звукам (то есть к таким источникам, которые не издают звук непрерывно, а звучат лишь при наступлении определенного события в игре).

Для изменения позиции, скорости и ориентации слушателя в пространстве следует использовать функцию FSOUND_3D_Listener_SetAttributes. Вот ее синтаксис:

Void F_API FSOUND_3D_Listener_SetAttributes(const F_FLOAT_API *pos, const F_FLOAT_API *vel, F_FLOAT_API fx, F_FLOAT_API fy, F_FLOAT_API fz, F_FLOAT_API tx, F_FLOAT_API ty, F_FLOAT_API tz);

В качестве параметров эта функция получает указатель на триаду координат позиции (pos), указатель на вектор скорости (vel), X, Y и Z составляющие единичного вектора, определяющего фронтальную ориентацию головы слушателя (fx, fy, fz); X, Y и Z составляющие единичного вектора, определяющего вертикальную ориентацию головы слушателя (tx, ty, tz). Несмотря на тип void, функция, согласно официальной документации, возвращает TRUE, если ее выполнение было успешным, и FALSE в случае ошибки.

В отличие от DirectSound3D, в FMOD может быть не один, а несколько слушателей. Это сделано для игровых приставок, где одно игровое устройство могут использовать одновременно несколько игроков. Выбор текущего слушателя производится при помощи функции FSOUND_3D_Listener_SetCurrent.

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

FSOUND_Sample_Free(samp1); FSOUND_Close();

Обработка ошибок

Большинство функций FMOD, если иное не оговорено в документации, возвращают TRUE в случае успешного завершения. Если же в работе функции возникла ошибка, то возвращается FALSE. Для того чтобы получить дополнительную информацию об ошибке, следует воспользоваться функциями FSOUND_GetError и FMOD_ErrorString. Последняя функция является макросом, поэтому необходимо включить заголовочный файл FMOD_errors.h.

Функция FSOUND_GetError не требует параметров и возвращает код ошибки, возникшей при выполнении функции FMOD. Макрос FMOD_ErrorString получает этот код в качестве параметра и возвращает текстовое описание ошибки. Вот пример вызова этих функций:

/* вывод сообщения об ошибке в консольном режиме */ printf("Error: %s\n", FMOD_ErrorString(FSOUND_GetError()));

Управление ресурсами и звуковые платы нижней ценовой категории

Сегодня существуют различные по производительности и возможностям звуковые карты. Одни из них способны поддерживать до 100 аппаратных каналов для воспроизведения 3D звука, другие - не более четырех. Было бы недальновидно при разработке игр ориентироваться на "слабые" звуковые карты. Однако ошибка, которая может возникнуть при нехватке аппаратных каналов в игре с большим количеством источников звука, может сделать игру совершенно неработоспособной на указанной группе звуковых карт. В качестве выхода из данной ситуации FMOD предлагает использовать функцию FSOUND_SetMinHardwareChannels.

Эта функция вызывается один раз перед вызовом FSOUND_Init и устанавливает минимальнное количество аппаратных каналов, которое должно поддерживаться звуковой картой. После этого либо все из указанного при вызове FSOUND_SetMinHardwareChannels числа каналов будут воспроизводится с использованием аппаратных каналов, либо аппаратная поддержка использоваться не будет и микширование каналов будет происходить программным путем. Иными словами, например, если у вас 16 звуков и карта имеет такое же или большее число аппаратных каналов, то воспроизведение будет идти через эти каналы. Если окажется, что у карты всего 4 канала, то смешивание всех звуков будет выполняться программно.

Поддержка приоритетов

В FMOD реализована система приоритетов. Если множество источников звука должны воспроизводиться на ограниченном числе каналов, то некоторые из них могут быть более важными, чем другие. Если, например, главным действующим лицом в игре выступает стрелок, то воспроизведение звука выстрела было бы, вероятно, самым важным. Так что этому источнику звука (выстрел) следовало бы установить самый высокий приоритет посредством FSOUND_SetPriority. Менее важные звуки не будут воспроизводиться, если уже заняты все доступные каналы.

Заключение

Изложенный выше материал является необходимым для того, чтобы познакомиться с возможностями FMOD в области работы с объёмным звуком и начать использовать эту библиотеку в своих программах. Но одной этой статьи недостаточно, чтобы узнать о всех возможностях библиотеки FMOD. Следующим шагом может стать изучение примеров, входящих в дистрибутивный пакет FMOD.

Культура модификации игр зародилась ещё в древние времена. Самое раннее, что я помню, это Wolfenstein 3D (1992 год). Если не ошибаюсь, можно было рисовать свои карты, а потом и новых врагов, заменять текстуры и звуки. Главным препятствием в моддинге является разбор неизвестных форматов данных. Оставим моральные аспекты этого явления для других ресурсов, и остановимся на технических сложностях, которые могут возникнуть в этом нелегком деле.

У меня накопилось довольно много историй такого рода, от самых простых, типа разбора простейшего архива, где в одном файле хранятся много тысяч файлов игры, до замены 3D-моделей, исследования и написания нестандартных кодеков звука. Расскажу одну из них, средней сложности.

Допустим, у вас появилось желание заменить определённые фразы в игре, или вообще замахнуться на полную озвучку на каком-нибудь языке, для которого у разработчиков не хватило сил или ресурсов. Казалось бы, надо только записать звук, найти где он находится в игре, и заменить нужные файлы. Но не всегда это бывает просто, например, в последних играх из серии Batman: Arkham используется звуковой движок wwise, который уже довольно давно интегрирован в Unreal Engine.

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

Для начала посмотрим звуковые файлы. Они как обычно лежат в папке audio и собраны в один большой пакет, с неожиданным расширением.WAD (привет DOOM). При желании даже можно извлечь из него все звуки, но это будет несколько тысяч безымянных файлов, и найти среди них что-то будет весьма проблематично, разве что «вручную» переслушивать их все. Надо сказать, что чаще всего бывает проще. Разработчики, для своего же удобства, оставляют где-нибудь файл со списком фраз. Но это не тот случай.

Логично предположить, что раз сама игра как-то находит нужные звуки и субтитры к ним, значит, эта информация где-то содержится в файлах, надо только её найти. Нигде в папках для локализации тексты не обнаруживаются, значит они разбросаны по отдельным уровням игры, как это часто бывает. Возьмем для примера один из.upk файлов с названием, похожим на уровень, и распакуем его. Благо, инструменты для этого имеются, даже с исходными текстами.

Внутри довольно быстро обнаруживаются файлы типа.RDialogueEvent, в которых невооруженным глазом видны тексты фраз на 11 языках.

Имена файлов похожи на имена исходных звуков. Замечательно, теперь осталось только найти соответствие между ними и звуковыми файлами. Вот только тут и начинаются проблемы. В звуковом пакете конечно есть идентификаторы. Это 30-битный хеш, который всегда используются в wwise для звуков, но к сожалению нигде среди файлов диалога их найти не удаётся. Везде одни непонятные цифры, ничего похожего на ID звука нет, они сразу были бы заметны. С другой стороны, это и понятно, ведь движок не так прост, и нельзя просто так взять и проиграть звуковой файл в игре. Он содержится в аудио-банке, у него множество свойств, накладывающих различные эффекты и т.д.

И тут оказывается, что в каждой папке с диалогом есть файл.akbank - видимо это и есть аудио банк wwise.

Вот у него внутри как раз очень много идентификаторов, перепробовав которые наугад, мы обнаруживаем, что один из них (выделен зеленым) имеется в звуковом пакете. Если мы извлечем оттуда данные по этому идентификатору, то получим некий сегмент из слепленных вместе нескольких звуков. Сконвертируем эти звуки из внутреннего формата wwise в обычные ogg. Да, действительно, в одном из них Бэтмен говорит: «I don"t have time for this», а в другом файле ему отвечают. И фразы как раз соответствуют текстам именно этого диалога.

Уже неплохо! В принципе, на этом можно было бы и остановиться: все диалоги разложены по папкам, для каждого из них есть банк со ссылкой на звуковой сегмент. Мы конечно не знаем, где какой файл, но разрезать сегмент на части, послушать и расставить по местам несколько фраз (а их в диалогах обычно бывает всего 3-4 штуки) можно и вручную.

Но мы не ищем легких путей. Разбираться, так до конца. Проверим на всякий случай, вдруг звуки идут прямо по порядку? Конечно же нет, они перепутаны. Как ни крути, где-то должна быть информация о связи звуков в сегменте с текстом диалога. Я довольно долго копался в разных файлах, в надежде что-то обнаружить, но всё бесполезно. Хорошо. Раз такое дело, распакуем все пакеты игры. Это несколько гигабайт, ну ничего, первый раз что-ли? Вот только полный поиск по всем данным игры также ничего не дал. Единственное место, где есть идентификаторы звуков, это аудио банк. Выходит, связь идёт только через него. Ничего не поделаешь, придется лезть внутрь и разбираться, как он устроен.

Теперь, для верности, найдём в игре какой-нибудь диалог, который можно быстро проверять. После эффектного вступления с очаровательной девушкой-репортёршей и маски-шоу, Бэтмена захватывает Hugo Strange. Он говорит пару фраз, начинающихся с «I feel I should thank you», потом уходит, и начинается игра. Именно здесь происходит первое сохранение. Этот момент нам подойдёт.

Найдём фразу злодея в файлах. Она оказывается в пакете OW_E8_Ch1z_Anim. Так сразу и не догадаешься. Внутри всего один диалог, в котором содержится всё начало игры. Это целых 24 фразы, но возможно это даже хорошо, в мешанине кодов легче найти число 24, чем 1 или 2. Итак, мы собирались изучить содержимое.akBank

Формат банков wwise оказывается уже частично исследован. Будем надеяться что этой информации хватит для нашей цели. Судя по началу файла.akbank, в нем находятся сразу 5 аудио банков для 5 языков, первым идёт банк INT (английский) - его мы и посмотрим.

Сначала там имеется непонятная таблица после заголовка ВКРК, потом довольно много нулей (это видно на прошлой картинке), потом сегмент BKHD, и потом сегмент HIRC, в котором, по всей видимости, находится описание всех аудио-объектов. В данном случае у нас их 79 штук (0x4F выделено зеленым). Как утверждает описание, объекты в сегменте идут один за другим, для каждого указан тип (1 байт), потом 32-битная длина, и ID. Длина и содержимое объекта отличается в зависимости от типа.

Объекты тип 2 - это собственно звуки. Тип выделен красным, длина - желтым. У каждого из них указан ID самого объекта (зеленым) и ID звукового файла (фиолетовым), где он содержится. Ниже видно начало следующего объекта такого же типа.

Объекты 3 - звуковые действия, похоже каждое из них это «проиграть звук», с какими-то неизвестными нам параметрами, но в каждом из них есть свой ID (серым) и ID звука, который собственно нужно проиграть (зеленым).

Объекты 4 - звуковые события. Очень короткие записи, в которых только и есть, что ID события (голубым), а также указано, что оно содержит только одно действие, и ID этого самого действия (серым).

Ну вот, похоже у нас имеется 24 цепочки событий следующего вида:

Событие -> действие -> звук

Они связаны идентификаторами, и в итоге заканчиваются ссылками на звуковые файлы. Как же найти нужные файлы? Поискав эти коды, мы обнаруживаем их как раз в той самой таблице в начале банка. Видимо это таблица, в которой записано, где внутри звукового сегмента находятся отдельные звуки. И действительно, в ней как раз 24 элемента, и для каждого файла указан тот самый ID, который у нас был в звуковом объекте, смещение относительно начала, и длина. Поздравляем! Теперь у нас полностью прослеживается связь от аудио-событий в банках до отдельных звуковых файлов:

To есть как исходные данные у нас есть ID нескольких событий, по одному для каждой фразы диалога, и для каждого из них мы можем найти звуковой файл. Но как связать их теперь с самим диалогом?

Попробуем поискать где-нибудь эти идентификаторы. В файлах диалогов их опять нет. В папке есть еще какие-то очень короткие файлы.akevent - их тоже 24 штуки. Очевидно, это файлы аудио-событий. Внутри какие-то небольшие числа, у всех одинаковые, от них никакого толку. Единственное, что там есть разного, это как раз id аудио-событий, которые мы нашли в банке.

Опять тупик: есть идентификаторы для всех событий, но связи между ними и текстом диалога нет! На всякий случай сделаем тест: поменяем в нужном файле ID и запустим игру. Да, действительно, Хьюго открывает рот, но ничего не говорит. Значит это именно те данные, по которым игра находит нужный звук. Заодно отмечаем, что субтитр всё равно показывается. Значит тексты диалогов в нашем случае первичны, а от них уже идёт звук.

И тут я вспоминаю, что у движка UE3 есть привычка ссылаться на объекты пакета через их порядковый номер внутри пакета, то есть прямо как они упакованы внутри него. Посмотрим файл экспорта, который образуется у нас при распаковке пакетов:

Номера здесь десятичные, и начинаются с нуля, в игре же они начинаются с 1, поэтому получается, что файлы событий в экспорте идут под номерами 0x35-0x4С. Посмотрим, нет ли их где-то среди диалогов. Начинаем смотреть - и надо же, прямо в начале файла есть этот номер!

Вот и последнее недостающее звено. Заодно рядом обнаруживаем 0x2С - это номер файла банка. В случае если в папке вдруг будет несколько диалогов, их тоже можно будет отличить. Теперь мы полностью знаем, как по тексту диалога найти соответствующий звук.

Такая вот получилась довольно сложная схема взаимодействия. Похоже разработчики решили не заботиться об удобстве, и просто положились на внутренние механизмы движка, что и привело к такому результату в данном случае. А случаи, как я уже сказал, бывают самые разные. Структура файлов и связи между ними могут быть совершенно другие. Здесь у нас от текста диалога шла ссылка на звук. А бывает наоборот, первичным является звук, а к нему по идентификатору находится текст. Или первично событие скрипта игры, а от него идут ссылки и на звук, и на текст. Бывает, что файлы находятся не по имени, а по хешу. Но в любом случае, каким-то образом они все связаны, остаётся только найти эту связь.

В качестве последнего штриха попробуем проверить наши результаты. Найдём файл диалога именно от нужной нам фразы «I feel I should thank you» и заменим в нём 4B на 4C. Запускаем игру, и наш друг Хьюго вместо этой фразы многозначительно произносит: «It will be my legacy, a monument to your failure and if you try to stop me, I guarantee everyone will know your secret.»

Оставим на этом Бэтмена, исследование можно считать законченным. В письменном виде процесс выглядит быстро, но на самом деле каждый этап может сопровождаться долгим созерцанием 16-ричных цифр, без всякой надежды на то, что в какой-то момент они сложатся в осмысленные цепочки, и вы поймёте, что они значат. Но иногда это всё-таки происходит.

Музыкальные форматы в играх
Shiru (A.Semenov) mailto:shiru at mail dot ru

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

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

Потоковое аудио

Это не совсем музыкальный формат - это звук, как он есть, записанный в файл. Но этот звук вполне может быть музыкой, поэтому в контексте данной статьи потоковое аудио является также и музыкальным форматом. Потоковым оно называется потому, что файлу не требуется присутствовать в памяти целиком - достаточно подчитывать с носителя небольшие кусочки, декодировать (если требуется), и отправлять на воспроизведение. Потоковое аудио бывает со сжатием и без него.

Форматы потокового аудио без сжатия для хранения музыки в играх обычно не используются, из-за огромного размера: одна секунда стереозвука CD-качества (44100hz, 16bit) занимает 172 килобайта. Исключение ранее составлял CD-DA, формат аудио компакт-дисков. Но игр с музыкой в этом формате в последние годы не наблюдается - всегда находится, чем забить немногочисленные, по современным меркам, мегабайты CD/DVD-дисков.

Более подходящими для игрового применения являются аудиоформаты со сжатием. Существуют алгоритмы сжатия звука без каких-либо потерь качества (т.н. lossyless алгоритмы), но выигрыш в объёме у них крайне несерьёзный, поэтому наиболее распространены форматы сжатия с потерей качества (lossy алгоритмы). Популярные алгоритмы сжатия, дающие большой выигрыш в объёме конечного файла, используют идею "психоакустического кодирования" - динамического исключения из сигнала частот, плохо воспринимаемых человеческим слухом. Обычно выбирают такой уровень потерь, который малозаметен на слух. Алгоритмы сжатия звука обычно работают с фиксированным коэффициентом сжатия, для игр это обычно что-то около 11:1...7:1 (поток данных 128...192kb/s). Существует огромное количество форматов сжатия звука, но наиболее известными и используемыми из них являются MP3, WMA, OGG.

MP3 - наиболее старый, очень распространённый формат. Изначально появился, как формат сжатия звуковой дорожки для видеофильмов в формате VideoCD (полное название MP3 - MPEG Audio Layer III), но довольно быстро стал использоваться и сам по себе. Сейчас MP3 является промышленным стандартом. Использование звуковых файлов с MP3-сжатием в коммерческих игровых проектах, издающихся тиражом более 5000 копий, стоит денег - $2500 за один продукт (game license, подробнее о лицензировании смотрите ссылки в конце статьи). На сегодняшний день MP3 обеспечивает не лучшие показатели в соотношении размер/качество. Улучшенные варианты формата MP3 - MP3pro, например - при показателях, аналогичных WMA/OGG не завоевали особой популярности.

WMA - Windows Media Audio, формат, продвигаемый самой Microsoft как более совершенная альтернатива MP3, является примерно аналогичным по возможностям формату OGG. Его использование в программных продуктах для хранения звукового контента не требует лицензирования.

OGG - относительно новый формат сжатия звука, представляет наибольший интерес для разработчиков игр. Он не требует никакого лицензирования, его можно совершенно законно использовать бесплатно; при этом он обеспечивает более высокое качество звучания при одинаковом с MP3 размере, либо меньший размер при одинаковом качестве звука. Правда, декодирование OGG требует несколько больших вычислительных ресурсов, чем MP3/WMA. Программные кодеры и декодеры от создателя формата (Vorbis) распространяются с открытым исходным кодом.

Плюсы использования потокового аудио для хранения музыки:

  • Можно хранить музыку абсолютно любого технического уровня. В этом отношении данный формат универсален, и потенциально (особенно при сжатии с низким уровнем потерь) способен обеспечить наилучшее качество звучания
  • Ваши музыканты не ограничены возможностями формата, и могут использовать тот инструментарий для создания музыки, какой им удобен (т.е. подходящего музыканта будет легко найти)
  • Не требует большого количества оперативной памяти при проигрывании (поток данных читается с носителя небольшими порциями)
Минусы:
  • Для некоторых применений размер даже сжатого аудио может оказаться слишком большим - средней длины композиция в приличном качестве занимает 3-5 мегабайт (при использовании форматов со сжатием)
  • Уменьшить размер можно только за счёт существенного снижения качества (увеличения потерь при сжатии) и уменьшения длины композиций
  • Длительность звучания трека напрямую зависит от размера файла с ним
  • Декодирование сжатого аудио требует относительно больших ресурсов CPU, на маломощных платформах без аппаратного декодера оно может оказаться невозможным (в реальном времени)

Музыкальные форматы

Собственно музыкальными форматами являются форматы, содержащие не конечный звук, а только лишь информацию о том, как его получить. Т.е., информацию о том, когда и какие ноты какими звуками играть (и - необязательно - сами эти звуки). За счёт этого возможно достижение значительного выигрыша в объёме хранимой информации (размере файла). Получение окончательного звука (который услышит игрок) происходит непосредственно в процессе проигрывания музыки. Это отнимает некоторые вычислительные ресурсы, но в целом нагрузка не выше, чем при декодировании сжатого потокового аудио, а обычно даже меньше (проигрывание музыкальных форматов поддаётся аппаратному ускорению; на PC, к примеру, требуемая аппаратная поддержка встречается намного чаще, чем требуемая аппаратная поддержка для декодирования сжатого аудио).

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

Используемые в играх музыкальные форматы можно разделить на две подгруппы: MIDI и семейство трекерных форматов (т.н. трекерные модули, иногда также называемые просто модулями). Главное различие между этими двумя подгруппами - стандартные MIDI-файлы содержат в себе только ноты, тогда как в трекерных модулях помимо нот хранятся сэмплы, которыми эти ноты озвучиваются. Остальные отличия касаются, в основном, некоторых ограничений, накладывающих свою специфику при написании музыки.

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

Музыкальные форматы: MIDI

MIDI (Musical Instruments Digital Interface) - аппаратный интерфейс, а также стандарт, описывающий процесс обмена музыкальными данными между электронными музыкальными инструментами. Музыкальные данные - это не звук, это, говоря очень упрощённо, только информация о нажимаемых/отпускаемых клавишах синтезатора. MIDI - также стандарты хранения этой информации в файлах (наиболее известные варианты - .mid, .midi). MIDI можно в некотором приближении назвать "потоковым музыкальным форматом", т.к. для его воспроизведения нет необходимости иметь весь файл в памяти - можно подчитывать его по кусочкам, как и в случае с потоковым аудио. Но это единственное сходство между этими форматами.

Многие пользователи PC, услышав слово "миди", презрительно говорят что-то вроде - "а, это такие маленькие файлики, с ужасно звучащей музыкой" (особенно те, у кого ещё сохранились раритетные звуковые карты без качественных WaveTable-синтезаторов). Важно понимать, что звучание записанной в MIDI-файл композиции - это звучание синтезатора в вашем компьютере, через который содержимое файл воспроизводится, качество звучания напрямую зависит от качества синтезатора. Мало кто знает, что MIDI повсеместно используется при создании профессиональной электронной музыки (в т.ч. и для создания музыки к играм, для последующей записи в аудиоформат).

В настоящий момент единственным используемым принципом работы MIDI-синтезаторов на PC является т.н. WaveTable-синтез. Т.е., есть набор (банк) звуков различных инструментов (описанный стандартом, минимум 128 инструментов и 64 звука ударных), синтезатор воспроизводит ноты этими звуками. В MIDI-файле звуки инструментов не хранятся, а банки инструментов от разных производителей звуковых карт могут различаться (не составом инструментов, но особенностями их звучания). Поэтому с разными банками инструментов звучание одного и того-же MIDI-файла несколько изменяется, что иногда составляет определённую проблему. Написанная под один банк композиция может плохо звучать с другим (из-за различающегося баланса громкостей инструментов, например). Это-же накладывает и ограничение на творческую свободу музыканта - он ограничен только теми тембрами (инструментами), которые описывает стандарт. С другой стороны, отсутствие сэмплов инструментов в MIDI-файле очень сильно уменьшает его размер - огромной длины композиция может весить всего 50-100 килобайт, и при этом отлично сжиматься обычным ZIP`ом в несколько раз.

Есть несколько обратно совместимых стандартов MIDI - основной, General Midi (GM); расширение от Roland (GS); более продвинутое расширение от Yamaha (XG). Расширенные форматы обладают большим количеством инструментов в стандарте (минимум 226 для GS, минимум 480 для XG - не считая ударных), и дополнительными возможностями управления синтезом звука, за счёт которых можно разнообразить и улучшить качество звучания.

Для воспроизведения MIDI нужен MIDI-синтезатор в системе - на PC это может быть звуковая карта с аппаратным WaveTable синтезатором (GM/GS/XG, со своим банком звуков), либо простейшая звуковая карта (типа AC"97) с программным синтезатором (который отъедает часть производительности системы; программный GS-синтезатор со стандартным звуковым банком есть в составе DirectX). На устройствах типа мобильных телефонов это может быть простой аппаратный синтезатор (для программного синтеза мощности пока не те), причём не WaveTable, а одного из альтернативных способов синтеза (обычно это FM-синтез), очень приблизительно имитирующих звучание инструментов.

Если аппаратного синтезатора в системе нет, а для программного синтеза недостаточно ресурсов процессора/памяти - воспроизводить MIDI на таком устройстве невозможно.

Плюсы:

  • Очень маленький размер файлов
  • При использовании хорошего синтезатора с хорошим банком сэмплов - высокое качество звучания
  • При наличии аппаратного синтезатора - очень маленькая нагрузка на CPU (плеер только пересылает команды на синтезатор)
  • Музыканта, умеющего работать c MIDI, нетрудно будет найти
Минусы:
  • Зависимость качества звучания от используемого синтезатора
  • Различное звучание инструментов на разных синтезаторах (музыка, хорошо звучащая на одном синтезаторе, может ужасно звучать на другом, даже если эти синтезаторы одинаково высокого качества)
  • Некоторая однообразность звучания любой музыки на одном и том-же синтезаторе (за счёт того, что банк сэмплов для разных композиций обычно не меняется)

Музыкальные форматы: трекерная музыка

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

Трекер - это музыкальный редактор с определённым типом интерфейса (вертикальные столбцы цифр и букв вместо привычного для музыкантов нотного стана). Трекеры появились очень давно, ещё на первых домашних компьютерах, имевших простейшие устройства для синтеза звуков. Ноты озвучивались аппаратными средствами системы (например, через чип SID на C64, через чип AY на ZX128). Трекеры, использующие для озвучивания нот сэмплы, появились в конце 80-х на платформе AMIGA, а позже распространились и по всем остальным платформам, имеющим средства для воспроизведения цифрового звука.

Сам принцип работы трекеров накладывает определённые ограничения на возможности музыканта, с другой стороны, предоставляя не совсем обычные возможности управления звуком. В отличии от профессионального стандарта MIDI, это - любительский стандарт, разработанный любителями компьютерной музыки, а не производителями музыкального оборудования. Написание музыки в трекерах отличается от работы с профессиональными программными MIDI-секвенсорами. Основные особенности трекеров:

Жёсткая квантизация времени - ноты не могут начинать и прекращать звучать в произвольное время, а только на определённых позициях (это затрудняет исполнение некоторых эффектов, например, плавного взятия гитарного аккорда);
- Отсутствие полифонии на отдельно взятом канале (дорожке), одновременно может звучать ровно столько нот, сколько каналов в треке;
- Наличие "эффектов" - команд, влияющих на процесс воспроизведения каждой отдельно взятой ноты. Эффекты могут быть как вполне обычными (с музыкальной точки зрения) - вибрато, управление громкостью, портаменто; так и не вполне обычными - смещение начала сэмпла, управление фильтрами, и т.п.

Несмотря на некоторые ограничения (по сравнению c MIDI), хранение сэмплов в файле с композицией даёт очевидные преимущества - возможность использовать любые необходимые тембры, фрагменты исполненных "вживую" партий (гитарные рифы, барабанные лупы) - это позволяет поднять качество звучания, и сделать его более приближенным к "живому звучанию".

Существует большое количество трекерных форматов - как правило, каждый новый редактор помимо поддержки нескольких наиболее популярных форматов, имел и свой собственный формат. Форматы различаются возможностями и организацией данных внутри файла, но общая идея остаётся неизменной. Наиболее популярными являются четыре формата, ставшие стандартными (поддерживаются практически всеми редакторами): простые MOD (Sound Tracker/Pro Tracker) и S3M (Scream Tracker), и более совершенные XM (Fast Tracker) и IT (Impulse Tracker).

Самый первый трекерный формат - MOD (от слова module, поэтому трекерную музыку и называют модулями) - имел скромные возможности: 4 канала, максимум 15 инструментов (только 8-bit сэмплы, плюс возможность простейшей петли в сэмпле), скудный набор эффектов. Позднее появилась модификация MOD с возможностью использовать 31 инструмент и 8 каналов.

S3M несколько расширяет возможности MOD - в частности, можно использовать до 32-х каналов, увеличенное количество эффектов. Но формат сэмплов по-прежнему ограничен 8-bit.

XM и IT дают гораздо большие возможности для творчества, и заметно более высокое качество звучания. Большое количество каналов (зависит от редактора и поддержки со стороны плеера), большое количество эффектов, 16-битные сэмплы (они могут быть зациклены как прямой, так и двунаправленной петлёй), 64 инструмента. Инструменты в XM/IT не являются синонимом сэмплу - это описание, какие сэмплы использовать для определённых диапазонов нот инструмента (т.н. слои, это нужно для повышения качества имитации живых инструментов), громкостная и панорамная огибающая, и некоторые другие параметры.

Воспроизведение MOD/S3M требует несколько меньших ресурсов CPU, чем воспроизведение более сложных XM/IT. Нагрузка на CPU также зависит от количества каналов в модуле и от используемого алгоритма интерполяции при микшировании (от качества интерполяции сильно зависит качество звучания).

Файлы трекерной музыки могут занимать от сотен байт до нескольких мегабайт. Размер файла напрямую зависит от количества и качества используемых сэмплов. В среднем более-менее прилично звучащий модуль (причём любой длительности) занимает 200-500 килобайт.

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

Существуют модификации стандартных трекерных форматов с использованием сжатия сэмплов посредством OGG/MP3. Это форматы MO3 (объединяет в себе форматы IT/XM/S3M/MTM/MOD) и OXM (стандартный XM, но с использованием OGG для упаковки сэмплов). Оба формата используют сжатие только для тех сэмплов, для которых оно даёт выгоду в размере. Сжатие сэмплов приводит к существенному уменьшению занимаемого на диске объёма при практически незаметном на слух снижении качества. Сэмплы хранятся сжатыми только в файле, при загрузке модуля они разворачиваются в памяти, поэтому само проигрывание таких модулей не даёт увеличения нагрузки на CPU, но модуль при воспроизведении будет занимать столько-же оперативной памяти, сколько и неупакованный. Использование сжатия сэмплов может позволить как просто уменьшить размер файла, так и повысить качество звучания без изменения размера (за счёт использования более качественных сэмплов). Данная технология может быть непригодной для использования на маломощных платформах - сэмплы могут слишком долго декодироваться (загружаться).

Плюсы:

  • Потенциально могут обеспечить лучшее соотношение размер/качество, когда размер файла с музыкой сильно ограничен (100-500кб)
  • Увеличение длительности композиции очень мало увеличивает объём файла
Минусы:
  • Трекерные форматы не настолько гибки, как потоковое аудио
  • Проигрываемый модуль занимает оперативную память (актуально для систем с ограниченным количеством RAM, например, некоторые КПК)
  • Довольно нестандартный подход к написанию музыки, отличающийся от обычной нотной записи, это осложняет освоение трекеров "обычными" музыкантами

Что выбрать?

Ознакомившись со спецификой различных музыкальных форматов, мы можем наконец перейти к собственно проблеме выбора наиболее подходящего из них, в рамках конкретного проекта. Для начала нужно определить критерии отбора: какие возможности имеет платформа, на которой работает ваша игра, какие технические ограничения имеются. В частности - критичен-ли объём занимаемой музыкой на носителе и, при проигрывании, оперативной памяти; критична-ли нагрузка на CPU; есть-ли аппаратные возможности для проигрывания музыки (декодер MP3, MIDI-синтезатор).

Потоковое аудио резонно использовать, когда нет жёстких ограничений по объёму, занимаемому на носителе, и достаточно мощности CPU для декодирования (либо есть аппаратный декодер). Также, если необходимо создать очень качественное музыкальное оформление (примеры: радиостанции в серии игр GTA; записанная вживую музыка), других вариантов, кроме потокового аудио, просто не остаётся. Большим плюсом этого формата является отсутствие проблем с навыками (или их отсутствием) использования различного оборудования и программ ваших музыкантов - они могут свободно использовать те средства, которые им наиболее удобны, т.к. результат всегда можно записать в аудиофайл.

Если имеются жёсткие ограничения по объёму занимаемой памяти, лучше задуматься о музыкальных форматах - MIDI или трекерной музыке. Выбирать между этими двумя направлениями нужно, исходя из возможности воспроизведения форматов на целевой платформе (MIDI на Palm или GBA, скажем, особо не поиграешь) и ограничений в размерах файлов. Также не последнюю роль играют возможности ваших музыкантов (т.к. создание качественной музыки в этих форматах требует определённых навыков).

Сейчас популярно использовать в условиях сильного ограничения объёма памяти на носителе (обычно это shareware игры на PC), отводимого под музыку, одно-двухминутных отрывков потокового аудио (обычно OGG) в очень низком качестве (от 56 kbps и ниже, в 22050hz моно - это около 500-600 килобайт). В таких случаях стоит задуматься о возможности использования трекерных форматов - мощности CPU в этом случае на воспроизведение хватит, зато при том-же или меньшем размере файла можно получить существенно более качественное, чистое звучание (возможно, менее живое - но здесь всё зависит от квалификации музыканта).

Если проект на PC, а место под музыку ограничено очень сильно (скажем, 500 килобайт на всё музыкальное оформление), можно задуматься об использовании вместо потокового аудио и трекерных модулей MIDI-файлов. Проблему с различием звучания при использовании разных звуковых банков можно решить, используя программный MIDI-синтезатор DirectX - Microsoft Software GS MIDI Synthezer. Он использует идущий в поставке DirectX трёхмегабайтный GS-банк, и, если писать MIDI-трек специально в расчёте на этот синтезатор, можно получить весьма приличный звук при минимальном расходе памяти на музыкальное оформление (в 500 килобайт свободно поместится десяток неупакованных 5-10 минутных MIDI-файлов). Также можно использовать свой программный MIDI-синтезатор, или свой DLS-банк - в этом случае вы получите все преимущества работы с музыкой посредством MIDI, и возможность использовать собственные тембры, свойственную трекерным форматам.

На КПК и ручных игровых приставках наиболее подходящим сейчас форматом является трекерная музыка (конкретный формат выбирается в зависимости от мощности CPU) - объёмы носителей, в отличии от мощности процессоров, там пока не доросли до возможности свободного использования потокового аудио в играх.

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

Культура модификации игр зародилась ещё в древние времена. Самое раннее, что я помню, это Wolfenstein 3D (1992 год). Если не ошибаюсь, можно было рисовать свои карты, а потом и новых врагов, заменять текстуры и звуки. Главным препятствием в моддинге является разбор неизвестных форматов данных. Оставим моральные аспекты этого явления для других ресурсов, и остановимся на технических сложностях, которые могут возникнуть в этом нелегком деле.

У меня накопилось довольно много историй такого рода, от самых простых, типа разбора простейшего архива, где в одном файле хранятся много тысяч файлов игры, до замены 3D-моделей, исследования и написания нестандартных кодеков звука. Расскажу одну из них, средней сложности.

Допустим, у вас появилось желание заменить определённые фразы в игре, или вообще замахнуться на полную озвучку на каком-нибудь языке, для которого у разработчиков не хватило сил или ресурсов. Казалось бы, надо только записать звук, найти где он находится в игре, и заменить нужные файлы. Но не всегда это бывает просто, например, в последних играх из серии Batman: Arkham используется звуковой движок wwise, который уже довольно давно интегрирован в Unreal Engine.

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

Для начала посмотрим звуковые файлы. Они как обычно лежат в папке audio и собраны в один большой пакет, с неожиданным расширением.WAD (привет DOOM). При желании даже можно извлечь из него все звуки, но это будет несколько тысяч безымянных файлов, и найти среди них что-то будет весьма проблематично, разве что «вручную» переслушивать их все. Надо сказать, что чаще всего бывает проще. Разработчики, для своего же удобства, оставляют где-нибудь файл со списком фраз. Но это не тот случай.

Логично предположить, что раз сама игра как-то находит нужные звуки и субтитры к ним, значит, эта информация где-то содержится в файлах, надо только её найти. Нигде в папках для локализации тексты не обнаруживаются, значит они разбросаны по отдельным уровням игры, как это часто бывает. Возьмем для примера один из.upk файлов с названием, похожим на уровень, и распакуем его. Благо, инструменты для этого имеются, даже с исходными текстами.

Внутри довольно быстро обнаруживаются файлы типа.RDialogueEvent, в которых невооруженным глазом видны тексты фраз на 11 языках.

Имена файлов похожи на имена исходных звуков. Замечательно, теперь осталось только найти соответствие между ними и звуковыми файлами. Вот только тут и начинаются проблемы. В звуковом пакете конечно есть идентификаторы. Это 30-битный хеш, который всегда используются в wwise для звуков, но к сожалению нигде среди файлов диалога их найти не удаётся. Везде одни непонятные цифры, ничего похожего на ID звука нет, они сразу были бы заметны. С другой стороны, это и понятно, ведь движок не так прост, и нельзя просто так взять и проиграть звуковой файл в игре. Он содержится в аудио-банке, у него множество свойств, накладывающих различные эффекты и т.д.

И тут оказывается, что в каждой папке с диалогом есть файл.akbank - видимо это и есть аудио банк wwise.

Вот у него внутри как раз очень много идентификаторов, перепробовав которые наугад, мы обнаруживаем, что один из них (выделен зеленым) имеется в звуковом пакете. Если мы извлечем оттуда данные по этому идентификатору, то получим некий сегмент из слепленных вместе нескольких звуков. Сконвертируем эти звуки из внутреннего формата wwise в обычные ogg. Да, действительно, в одном из них Бэтмен говорит: «I don"t have time for this», а в другом файле ему отвечают. И фразы как раз соответствуют текстам именно этого диалога.

Уже неплохо! В принципе, на этом можно было бы и остановиться: все диалоги разложены по папкам, для каждого из них есть банк со ссылкой на звуковой сегмент. Мы конечно не знаем, где какой файл, но разрезать сегмент на части, послушать и расставить по местам несколько фраз (а их в диалогах обычно бывает всего 3-4 штуки) можно и вручную.

Но мы не ищем легких путей. Разбираться, так до конца. Проверим на всякий случай, вдруг звуки идут прямо по порядку? Конечно же нет, они перепутаны. Как ни крути, где-то должна быть информация о связи звуков в сегменте с текстом диалога. Я довольно долго копался в разных файлах, в надежде что-то обнаружить, но всё бесполезно. Хорошо. Раз такое дело, распакуем все пакеты игры. Это несколько гигабайт, ну ничего, первый раз что-ли? Вот только полный поиск по всем данным игры также ничего не дал. Единственное место, где есть идентификаторы звуков, это аудио банк. Выходит, связь идёт только через него. Ничего не поделаешь, придется лезть внутрь и разбираться, как он устроен.

Теперь, для верности, найдём в игре какой-нибудь диалог, который можно быстро проверять. После эффектного вступления с очаровательной девушкой-репортёршей и маски-шоу, Бэтмена захватывает Hugo Strange. Он говорит пару фраз, начинающихся с «I feel I should thank you», потом уходит, и начинается игра. Именно здесь происходит первое сохранение. Этот момент нам подойдёт.

Найдём фразу злодея в файлах. Она оказывается в пакете OW_E8_Ch1z_Anim. Так сразу и не догадаешься. Внутри всего один диалог, в котором содержится всё начало игры. Это целых 24 фразы, но возможно это даже хорошо, в мешанине кодов легче найти число 24, чем 1 или 2. Итак, мы собирались изучить содержимое.akBank

Формат банков wwise оказывается уже частично исследован. Будем надеяться что этой информации хватит для нашей цели. Судя по началу файла.akbank, в нем находятся сразу 5 аудио банков для 5 языков, первым идёт банк INT (английский) - его мы и посмотрим.

Сначала там имеется непонятная таблица после заголовка ВКРК, потом довольно много нулей (это видно на прошлой картинке), потом сегмент BKHD, и потом сегмент HIRC, в котором, по всей видимости, находится описание всех аудио-объектов. В данном случае у нас их 79 штук (0x4F выделено зеленым). Как утверждает описание, объекты в сегменте идут один за другим, для каждого указан тип (1 байт), потом 32-битная длина, и ID. Длина и содержимое объекта отличается в зависимости от типа.

Объекты тип 2 - это собственно звуки. Тип выделен красным, длина - желтым. У каждого из них указан ID самого объекта (зеленым) и ID звукового файла (фиолетовым), где он содержится. Ниже видно начало следующего объекта такого же типа.

Объекты 3 - звуковые действия, похоже каждое из них это «проиграть звук», с какими-то неизвестными нам параметрами, но в каждом из них есть свой ID (серым) и ID звука, который собственно нужно проиграть (зеленым).

Объекты 4 - звуковые события. Очень короткие записи, в которых только и есть, что ID события (голубым), а также указано, что оно содержит только одно действие, и ID этого самого действия (серым).

Ну вот, похоже у нас имеется 24 цепочки событий следующего вида:

Событие -> действие -> звук

Они связаны идентификаторами, и в итоге заканчиваются ссылками на звуковые файлы. Как же найти нужные файлы? Поискав эти коды, мы обнаруживаем их как раз в той самой таблице в начале банка. Видимо это таблица, в которой записано, где внутри звукового сегмента находятся отдельные звуки. И действительно, в ней как раз 24 элемента, и для каждого файла указан тот самый ID, который у нас был в звуковом объекте, смещение относительно начала, и длина. Поздравляем! Теперь у нас полностью прослеживается связь от аудио-событий в банках до отдельных звуковых файлов:

To есть как исходные данные у нас есть ID нескольких событий, по одному для каждой фразы диалога, и для каждого из них мы можем найти звуковой файл. Но как связать их теперь с самим диалогом?

Попробуем поискать где-нибудь эти идентификаторы. В файлах диалогов их опять нет. В папке есть еще какие-то очень короткие файлы.akevent - их тоже 24 штуки. Очевидно, это файлы аудио-событий. Внутри какие-то небольшие числа, у всех одинаковые, от них никакого толку. Единственное, что там есть разного, это как раз id аудио-событий, которые мы нашли в банке.

Опять тупик: есть идентификаторы для всех событий, но связи между ними и текстом диалога нет! На всякий случай сделаем тест: поменяем в нужном файле ID и запустим игру. Да, действительно, Хьюго открывает рот, но ничего не говорит. Значит это именно те данные, по которым игра находит нужный звук. Заодно отмечаем, что субтитр всё равно показывается. Значит тексты диалогов в нашем случае первичны, а от них уже идёт звук.

И тут я вспоминаю, что у движка UE3 есть привычка ссылаться на объекты пакета через их порядковый номер внутри пакета, то есть прямо как они упакованы внутри него. Посмотрим файл экспорта, который образуется у нас при распаковке пакетов:

Номера здесь десятичные, и начинаются с нуля, в игре же они начинаются с 1, поэтому получается, что файлы событий в экспорте идут под номерами 0x35-0x4С. Посмотрим, нет ли их где-то среди диалогов. Начинаем смотреть - и надо же, прямо в начале файла есть этот номер!

Вот и последнее недостающее звено. Заодно рядом обнаруживаем 0x2С - это номер файла банка. В случае если в папке вдруг будет несколько диалогов, их тоже можно будет отличить. Теперь мы полностью знаем, как по тексту диалога найти соответствующий звук.

Такая вот получилась довольно сложная схема взаимодействия. Похоже разработчики решили не заботиться об удобстве, и просто положились на внутренние механизмы движка, что и привело к такому результату в данном случае. А случаи, как я уже сказал, бывают самые разные. Структура файлов и связи между ними могут быть совершенно другие. Здесь у нас от текста диалога шла ссылка на звук. А бывает наоборот, первичным является звук, а к нему по идентификатору находится текст. Или первично событие скрипта игры, а от него идут ссылки и на звук, и на текст. Бывает, что файлы находятся не по имени, а по хешу. Но в любом случае, каким-то образом они все связаны, остаётся только найти эту связь.

В качестве последнего штриха попробуем проверить наши результаты. Найдём файл диалога именно от нужной нам фразы «I feel I should thank you» и заменим в нём 4B на 4C. Запускаем игру, и наш друг Хьюго вместо этой фразы многозначительно произносит: «It will be my legacy, a monument to your failure and if you try to stop me, I guarantee everyone will know your secret.»

Оставим на этом Бэтмена, исследование можно считать законченным. В письменном виде процесс выглядит быстро, но на самом деле каждый этап может сопровождаться долгим созерцанием 16-ричных цифр, без всякой надежды на то, что в какой-то момент они сложатся в осмысленные цепочки, и вы поймёте, что они значат. Но иногда это всё-таки происходит.

Зачем извлекать звук с игры? Что мало музыкальных сайтов?

Да дело в том, что искать замучаешься мелодии с игр. А тут игры завалялись на компьютере с хорошей электронной музыкой. Мне, как раз в то время нужно было по срочному сделать и озвучить его звуковыми эффектами. Вот и задумался, а не стянуть ли звук с игры. Игра была в формате Java-для мобильного телефона и так просто не поддавалась открытию её директории, не через какую программу.

Теперь извлекать звук с игр для меня не проблема. Помогла мне в этом одна мощная программа UniExtractor (скачать) Она предназначена для извлечения повреждённых архивов, таких как-7zip, WinRAR и других сжатых файлов. Ну и сами инсталляторы программ распаковывает без проблем. А Java-игра, как раз и является инсталлятором. После распаковки простой игры, пробовал извлечь звук с более сложной. Программа UniExtractor справилась и с играми для операционной системы Android. На распаковку уходит совсем немного времени. Примерно одну минуту. За это время на вряд бы вы нашли в интернете подходящий звук. Приступаем к делу.

Извлекаем звук с игры

Для разархивирования, как я выше упоминал, воспользуемся специальным распаковщиком архивов-Uniextractor . Программа не нужно отдельно запускать, а лишь щёлкнуть правой клавишей мышки по инсталлятору игры. В контекстном меню выбрать пункт-Извлечь с помощью Uniextractor.

Процесс распаковки.

Теперь, мы можем видеть два файла с одинаковым названием. Первый, это сам инсталлятор игры, а второй, это распакованный инсталлятор, в виде папки с файлами. Открываем папку и ищем в ней ещё одну, с названием app.

В этой папке находятся еще две, c аудио файлами. Они могут называться по-разному. Но обычно, это Music и Sound. В общем если их нет, тогда придётся все папки пересмотреть.

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

Это полезно знать:




Есть вопросы?

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: