ADX (формат файла)
Разработчик(и) | Промежуточное ПО CRI |
---|---|
Первоначальный выпуск | 1996 |
Платформа | Кросс-платформенный |
Тип | Кодек / формат файла |
Лицензия | Собственный |
Веб-сайт | Промежуточное ПО CRI |
CRI ADX — это собственный аудиоконтейнер и формат сжатия, разработанный CRI Middleware специально для использования в видеоиграх ; он получен из ADPCM, но со сжатием с потерями . Его наиболее примечательной особенностью является функция зацикливания, которая оказалась полезной для фоновых звуков в различных играх, использующих этот формат, включая многие игры для Sega Dreamcast , а также некоторые для PlayStation 2 , GameCube и Wii игры . Одной из первых игр, использовавших ADX, была Burning Rangers для Sega Saturn . Примечательно, что Sonic the Hedgehog серия , начиная с поколения Dreamcast, и большинство игр Sega для домашних видеоконсолей и ПК, начиная с Dreamcast, продолжают использовать этот формат для записи звука и голоса. Jet Set Radio Future для оригинальной Xbox также использовал этот формат. [1]
В набор инструментов ADX также входит родственный формат AHX, в котором используется вариант аудио MPEG-2 , предназначенный специально для голосовых записей, и пакетный архив AFS для объединения нескольких дорожек CRI ADX и AHX в один файл-контейнер.
Версия 2 формата (ADX2) использует расширения HCA и HCA-MX, которые обычно объединяются в файл-контейнер с расширениями ACB и AWB. Расширение AWB не следует путать с аудиоформатом с тем же расширением , оно в основном содержит двоичные данные для файлов HCA.
Общий обзор
[ редактировать ]CRI ADX — это аудиоформат с потерями, но в отличие от других форматов, таких как MP3 , он не применяет психоакустическую модель к звуку , чтобы уменьшить его сложность. Вместо этого модель ADPCM сохраняет выборки, записывая ошибку относительно функции прогнозирования, что означает, что большая часть исходного сигнала выдерживает процесс кодирования; торговля точностью представления по размеру с использованием небольших размеров выборки, обычно 4 бита. Толерантность слуховой системы человека к создаваемому этим шуму делает потерю точности едва заметной.
Как и другие форматы кодирования, CRI ADX поддерживает частоты до 96000 Гц. однако глубина выходной выборки зафиксирована на уровне 16 бит, как правило, из-за недостаточной точности из-за использования выборки небольшого размера. Он поддерживает несколько каналов, но, похоже, существует неявное ограничение на стереозвук (2 канала), хотя сам формат файла может представлять до 255 каналов. Единственной особенно отличительной особенностью, которая отличает CRI ADX от других форматов ADPCM, является встроенная функция зацикливания, позволяющая аудиоплееру при необходимости переходить назад после достижения одной указанной точки дорожки для создания связного цикла; гипотетически, эту функцию можно было бы использовать и для пропуска вперед, но это было бы излишним, поскольку вместо этого звук можно было бы просто обрезать с помощью программы редактирования.
Для воспроизведения, помимо собственного программного обеспечения CRI Middleware, существует несколько плагинов для WinAmp, а также инструменты преобразования WAV. В FFmpeg также реализована поддержка CRI ADX, но его декодер жестко запрограммирован, поэтому может правильно декодировать только ADX с частотой 44100 Гц.
Техническое описание
[ редактировать ]Спецификация CRI ADX не находится в свободном доступе, однако наиболее важные элементы структуры были реконструированы и задокументированы в различных местах в Интернете. Следует отметить, что архивные файлы AFS, в которые иногда упаковываются CRI ADX, представляют собой простой вариант архива , в котором для идентификации содержимого используются числовые индексы, а не имена.
Формат диска ADX определяется в формате big-endian . Идентифицированные разделы основного заголовка приведены ниже:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | А | Б | С | Д | И | Ф | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0 | 0x80 | 0x00 | Смещение авторских прав | Тип кодировки | Размер блока | Образец битовой глубины | Количество каналов | Частота дискретизации | Всего образцов | |||||||
0x10 | Частота верхних частот | Версия | Флаги | Примеры выравнивания контура (v3) | Цикл включен (v3) | Цикл включен (v3) | Индекс начала цикла (v3) | |||||||||
0x20 | Индекс байта начала цикла (v3) | Цикл включен (v4)
Индекс конца цикла (v3) |
Индекс начала цикла (v4)
Индекс байта конца цикла (v3) |
Индекс байта начала цикла (v4) | ||||||||||||
0x30 | Индекс конца цикла (v4) | Индекс байта конца цикла (v4) | Ноль или более байт пустого пространства | |||||||||||||
??? | [CopyrightOffset - 2] Строка ASCII (незавершенная): «(c)CRI» | |||||||||||||||
... | [CopyrightOffset + 4] Здесь начинаются аудиоданные |
Поля с пометкой «Неизвестно» содержат либо неизвестные данные, либо, по всей видимости, просто зарезервированы (т.е. заполнены нулевыми байтами). Поля, помеченные «v3» или «v4», но не оба, считаются «Неизвестными» в той версии, которой они не помечены. Этот заголовок может иметь длину всего 20 байт (0x14), что определяется смещением авторских прав, которое неявно удаляет поддержку цикла, поскольку эти поля отсутствуют.
Поле «Тип кодировки» должно содержать одно из:
- 0x02 для CRI ADX с предустановленными коэффициентами прогнозирования
- 0x03 для стандартного CRI ADX
- 0x04 для CRI ADX с экспоненциальной шкалой
- 0x10 или 0x11 для AHX
Поле «Версия» должно содержать одно из:
- 0x03 для CRI ADX «версия 3»
- 0x04 для CRI ADX «версия 4»
- 0x05 для варианта CRI ADX 4 без поддержки циклов.
При декодировании звука AHX поле версии не имеет никакого значения, и его можно смело игнорировать.
Файлы с типом кодирования «2» используют 4 возможных набора коэффициентов прогнозирования, перечисленных ниже:
Коэффициент 0 | Коэффициент 1 | |
---|---|---|
Установить 0 | 0x0000 | 0x0000 |
Набор 1 | 0x0F00 | 0x0000 |
Набор 2 | 0x1CC0 | 0xF300 |
Набор 3 | 0x1880 | 0xF240 |
Образец формата
[ редактировать ]Аудиоданные, закодированные CRI ADX, разбиваются на серию «блоков», каждый из которых содержит данные только для одного канала. Затем блоки распределяются по «кадрам», состоящим из одного блока каждого канала в порядке возрастания. Например, в стереофоническом (2-канальном) потоке он будет состоять из кадра 1: блок левого канала, блок правого канала; Кадр 2: слева, справа; и т. д. Блоки обычно всегда имеют размер 18 байт и содержат 4-битные выборки, хотя технически возможны и другие размеры, пример такого блока выглядит так:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Предиктор/Шкала | 32 4-битных семпла |
Индекс предиктора представляет собой 3-битное целое число, которое указывает, какой набор коэффициентов прогнозирования следует использовать для декодирования этого блока, а масштаб представляет собой 13-битное целое число без знака ( с прямым порядком байтов, как заголовок), которое по сути является усилением всех выборок в этом блоке. Каждая выборка в блоке должна быть декодирована в порядке битового потока, в порядке убывания. Например, когда размер выборки составляет 4 бита:
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|
Первый образец | Второй образец |
Сами образцы представлены не наоборот. Каждая выборка подписана, поэтому в этом примере значение может находиться в диапазоне от -8 до +7 (которое будет умножено на масштаб во время декодирования). Хотя заголовком возможна любая разрядность от 1 до 255, маловероятно, что когда-либо возникнут однобитовые выборки, поскольку они могут представлять только значения {0, 1}, {-1, 0} или {-1, 1}, которые не особенно полезны для кодирования музыки.
Декодирование CRI ADX
[ редактировать ]Кодировщик для ADX также можно создать, просто перевернув код для работы в обратном направлении. Примеры кода написаны с использованием C99 .
Прежде чем «стандартный» CRI ADX можно будет закодировать или декодировать, необходимо вычислить набор коэффициентов прогнозирования. Обычно это лучше всего делать на этапе инициализации:
#define M_PI acos(-1.0)
double a, b, c;
a = sqrt(2.0) - cos(2.0 * M_PI * ((double)adx_header->highpass_frequency / adx_header->sample_rate));
b = sqrt(2.0) - 1.0;
c = (a - sqrt((a + b) * (a - b))) / b; //(a+b)*(a-b) = a*a-b*b, however the simpler formula loses accuracy in floating point
// double coefficient[2];
coefficient[0] = c * 2.0;
coefficient[1] = -(c * c);
Этот код вычисляет коэффициенты прогнозирования для прогнозирования текущей выборки на основе двух предыдущих выборок. Как только он узнает коэффициенты декодирования, он может начать декодирование потока:
static int32_t* past_samples; // Previously decoded samples from each channel, zeroed at start (size = 2*channel_count)
static uint_fast32_t sample_index = 0; // sample_index is the index of sample set that needs to be decoded next
static ADX_header* adx_header;
// buffer is where the decoded samples will be put
// samples_needed states how many sample 'sets' (one sample from every channel) need to be decoded to fill the buffer
// looping_enabled is a boolean flag to control use of the built-in loop
// Returns the number of sample 'sets' in the buffer that could not be filled (EOS)
unsigned decode_adx_standard( int16_t* buffer, unsigned samples_needed, bool looping_enabled )
{
unsigned const samples_per_block = (adx_header->block_size - 2) * 8 / adx_header->sample_bitdepth;
int16_t scale[ adx_header->channel_count ];
if (looping_enabled && !adx_header->loop_enabled)
looping_enabled = false;
// Loop until the requested number of samples are decoded, or the end of file is reached
while (samples_needed > 0 && sample_index < adx_header->total_samples)
{
// Calculate the number of samples that are left to be decoded in the current block
unsigned sample_offset = sample_index % samples_per_block;
unsigned samples_can_get = samples_per_block - sample_offset;
// Clamp the samples we can get during this run if they won't fit in the buffer
if (samples_can_get > samples_needed)
samples_can_get = samples_needed;
// Clamp the number of samples to be acquired if the stream isn't long enough or the loop trigger is nearby
if (looping_enabled && sample_index + samples_can_get > adx_header->loop_end_index)
samples_can_get = adx_header->loop_end_index - sample_index;
else if (sample_index + samples_can_get > adx_header->total_samples)
samples_can_get = adx_header->total_samples - sample_index;
// Calculate the bit address of the start of the frame that sample_index resides in and record that location
unsigned long started_at = (adx_header->copyright_offset + 4 + \
sample_index / samples_per_block * adx_header->block_size * adx_header->channel_count) * 8;
// Read the scale values from the start of each block in this frame
for (unsigned i = 0 ; i < adx_header->channel_count ; ++i)
{
bitstream_seek( started_at + adx_header->block_size * i * 8 );
scale[i] = ntohs( bitstream_read( 16 ) );
}
// Pre-calculate the stop value for sample_offset
unsigned sample_endoffset = sample_offset + samples_can_get;
// Save the bitstream address of the first sample immediately after the scale in the first block of the frame
started_at += 16;
while ( sample_offset < sample_endoffset )
{
for (unsigned i = 0 ; i < adx_header->channel_count ; ++i)
{
// Predict the next sample
double sample_prediction = coefficient[0] * past_samples[i*2 + 0] + coefficient[1] * past_samples[i*2 + 1];
// Seek to the sample offset, read and sign extend it to a 32bit integer
// Implementing sign extension is left as an exercise for the reader
// The sign extension will also need to include a endian adjustment if there are more than 8 bits
bitstream_seek( started_at + adx_header->sample_bitdepth * sample_offset + \
adx_header->block_size * 8 * i );
int_fast32_t sample_error = bitstream_read( adx_header->sample_bitdepth );
sample_error = sign_extend( sample_error, adx_header->sample_bitdepth );
// Scale the error correction value
sample_error *= scale[i];
// Calculate the sample by combining the prediction with the error correction
int_fast32_t sample = sample_error + (int_fast32_t)sample_prediction;
// Update the past samples with the newer sample
past_samples[i*2 + 1] = past_samples[i*2 + 0];
past_samples[i*2 + 0] = sample;
// Clamp the decoded sample to the valid range for a 16bit integer
if (sample > 32767)
sample = 32767;
else if (sample < -32768)
sample = -32768;
// Save the sample to the buffer then advance one place
*buffer++ = sample;
}
++sample_offset; // We've decoded one sample from every block, advance block offset by 1
++sample_index; // This also means we're one sample further into the stream
--samples_needed; // And so there is one less set of samples that need to be decoded
}
// Check if we hit the loop end marker, if we did we need to jump to the loop start
if (looping_enabled && sample_index == adx_header->loop_end_index)
sample_index = adx_header->loop_start_index;
}
return samples_needed;
}
Большая часть вышеперечисленного должна быть простым на C. кодом ' ADX_header
' указатель относится к данным, извлеченным из заголовка, как описано ранее; предполагается, что они уже преобразованы в хост-эндиан. Эта реализация не является оптимальной, и внешние проблемы были проигнорированы, такие как конкретный метод расширения знака и метод получения битового потока из файла или сетевого источника. появятся наборы sample_needed (если стерео, например, будут пары) сэмплов Как только он завершится, в выходном буфере . Декодированные выборки будут в стандартном формате PCM с чередованием байтов с порядком байтов хоста , т. е. 16 бит слева, 16 бит справа, слева, справа и т. д. Наконец, если цикл не включен или не поддерживается, функция вернет количество пространств выборок, которые не использовались в буфере. Вызывающий может проверить, не равно ли это значение нулю, чтобы обнаружить конец потока и при необходимости удалить или записать тишину в неиспользуемые места.
Шифрование
[ редактировать ]CRI ADX поддерживает простую схему шифрования, в которой значения XOR из линейного конгруэнтного генератора псевдослучайных чисел со значениями блочного масштаба. Этот метод не требует больших вычислительных затрат для расшифровки (в соответствии с декодированием в реальном времени CRI ADX), но делает зашифрованные файлы непригодными для использования. Шифрование активно, когда значение «Флаги» в заголовке равно 0x08 . Поскольку XOR симметричен, для расшифровки используется тот же метод, что и для шифрования. Ключ шифрования представляет собой набор из трех 16-битных значений: множителя, приращения и начального значения для линейного конгруэнтного генератора (модуль равен 0x8000, чтобы значения оставались в 15-битном диапазоне допустимых блочных масштабов). Обычно все файлы ADX из одной игры используют один и тот же ключ.
Метод шифрования уязвим для атак с использованием известного открытого текста . Если известна незашифрованная версия того же аудио, поток случайных чисел можно легко получить и на его основе определить ключевые параметры, что делает каждый CRI ADX, зашифрованный тем же ключом, дешифруемым. Метод шифрования пытается усложнить эту задачу, не шифруя молчащие блоки (где все выборочные полубайты равны 0), поскольку их масштаб, как известно, равен 0.
Даже если зашифрованный CRI ADX является единственным доступным образцом, можно определить ключ, предполагая, что значения шкалы расшифрованного CRI ADX должны находиться в «низком диапазоне». Однако этот метод не обязательно находит ключ, используемый для шифрования файла. Хотя он всегда может определить ключи, которые выдают на первый взгляд правильный результат, ошибки могут остаться незамеченными. Это происходит из-за все более случайного распределения младших битов значений шкалы, которое становится невозможным отделить от случайности, добавляемой шифрованием.
AHX-декодирование
[ редактировать ]AHX — это реализация звука MPEG2 , и метод декодирования в основном такой же, как и стандартный, что позволяет просто демультиплексировать поток из контейнера ADX и пропускать его через стандартный декодер MPEG Audio, такой как mpg123 . «Частота дискретизации» и «общее количество выборок» заголовка CRI ADX обычно такие же, как и в исходном, но другие поля, такие как размер блока и разрядность выборки, обычно будут равны нулю, в дополнение к функциям цикла.
Ссылки
[ редактировать ]- ^ «imgur.com» . Имгур . Проверено 10 мая 2023 г.