Не смотря на то, что эта игра портирована с консоли Sony PlayStation, расширение XA вовсе не означает, что это плейстейшновский XA, а Exe-файл - эмулятор, как может показаться на первый взгляд.
Во-первых, если сравнивать версию для PS1 и PC, вторая имеет другую структуру папок, другое расширение файлов ресурсов (BZE вместо BZZ), сами данные - не сжаты, как в PS1-версии (хотя периодически они прерываются "FF" байтом, который выглядит как буква "я"); то что в PS1 версии было Vag-файлами, здесь имеет формат AIFF (только в заголовке почему-то для всех файлов прописана частота 44100 khz в виде байт "AC 44" - это Big Endian), а XA-файлы закодированы в так называемый IMA ADPCM.Чем декодировать?
Для этого уже существует инструмент "ImaEnc" от автора "Redsh". Скачать его можно здесь.Умеет не только декодировать, но и кодировать обратно. Приложение - консольное, но необходимые батники уже созданы. Работа проверена на Windows 10 x64. Можете сразу протестировать: распакуйте файлы в папку speech (в каталоге с игрой) и запустите Decode.bat. Можно внести изменения в Wav файл и закодировать его обратно с помощью Encode.bat.
Что это за формат такой?
Следующий текст взят отсюда:http://we.easyelectronics.ru/Soft/szhatie-zvuka-v-ima-adpcm.html
Автор: Lifelover
------------------------------------------------------------------------------------------------------------
Есть такой аудиокодек — IMA ADPCM. Сжимает аудио в 4 бита на сэмпл (250 кбит/с при частоте дискретизации 32 кГц, стерео), после чего, достаточно достоверно восстанавливает. А главное, очень быстро. Около 100 тактов на сэмпл на ядре AVR.
Как это работает?
Возьмём обычный файл звук.wav, закодированный в самом распространённом формате — PCM, 16 бит на сэмпл. Амплитуда каждого сэмпла представлена в нём числом от -32768 до 32767. Возьмём и заменим каждый сэмпл на разницу (дельта) между ним и предыдущим сэмлом. Получим формат DPCM — Differential PCM. Но тут мы ничего не выиграли, полученная дельта уже и в 16 бит не влезает. Получается число от -65535 до 65535.Но что, если уменьшить разрядность дельты? Если сигнал нарастает или убывает незначительно, всё будет хорошо. Но на крутых подъёмах и спусках изменение будет превышать разрядность дельты, возникнут искажения.
А если вместо дельты использовать дельту, умноженную на некоторый шаг? Например, если шаг равен 16, при изменении амплитуды сигнала на 64, дельта будет равна 4. Теперь, если сигнал изменяется значительно, процент искажений будет незначительным, однако при небольших изменениях сигнала, опять же, возникнут искажения, небольшие изменения могут просто пропасть.
Но что, если сделать шаг изменяемым. При небольших изменениях сигнала — маленький, при значительных — большой. Учитывая, что амплитуда сигнала — не случайная величина, а более-менее гладкая функция, мы сможем корректно изменять шаг, и минимизировать искажения.
Данный формат называется ADPCM — Adaptive Differential PCM. Осталось решить как рассчитывать изменение шага. Существует несколько алгоритмов. Здесь мы поговорим о IMA ADPCM. Это быстрый и простой алгоритм, оптимизированный для музыки.
Шаг берётся из специальной таблицы (ima_step_table), заполненной волшебными числами. Номер (step_index) шага в этой таблице изменяется после кодирования каждого сэмпла, в зависимости от скорости нарастания или убывания сигнала, по другой таблице (ima_index_table). Сжатый сэмпл занимает 4 бита (nibble) — 1 бит для знака и 3 для абсолютного значения (т.о. сжатый сэмпл может принимать значения от -7 до 7).
Сжатие:
step = step_table[step_index]
diff = sample - prev_sample
nibble = diff / step
step_index = step_index + index_table[nibble]
Восстановление:
step = step_table[step_index]При сжатии и восстановлении обязательно нужно учитывать возможные переполнения sample и step_index. Они случаются достаточно редко, но если случаются, то могут привести к плачевным последствиям. sample должен быть ограничен пределами от -32768 до 32767, step_index — от 0 до 88.
diff = nibble * step
sample = prev_sample + diff
step_index = step_index + index_table[nibble]
Кстати, этот кодек — отличный пример, показывающий превосходства программирования на ассемблере. Взять те же переполнения. При программировании на языке высокого уровня информация о переполнениях теряется, приходится использовать более длинный тип данных, и делать медленные сравнения. Что ужасно сказывается на производительности.
Ладно, вот моя реализация декодера.
/* -------------------------------------------------------------------------- */
#pragma once
/* -------------------------------------------------------------------------- */
typedef struct ima_state {
int16_t sample;
int8_t index;
} ima_state;
/* -------------------------------------------------------------------------- */
void imadec(ima_state *state, uint8_t value);
/* -------------------------------------------------------------------------- */
;------------------------------------------------------------------------------А вот пример использования
.global imadec
; ------------------------------------------------------------------------------
#define XL R26
#define XH R27
#define ZL R30
#define ZH R31
; ------------------------------------------------------------------------------
/*
R0 *
R1 zero
R18 sample
R19 sample
R20 step
R21 step
R22 value
R23 index
R24 state
R25 state
R26 XL
R27 XH
R30 ZL
R31 ZH
*/
;------------------------------------------------------------------------------
imadec:
movw XL,R24 ; state
ld R18,X+ ; sample
ld R19,X+
ld R23,X ; index
; load step
ldi ZL,lo8(step_table)
ldi ZH,hi8(step_table)
mov XL,R23
lsl XL
add ZL,XL
adc ZH,R1
lpm R20,Z+ ; step = step_table[index]
lpm R21,Z
; diff = (value + 0.5) * step / 4
clr XL ; diff = 0
clr XH
sbrs R22,2 ; if(value & 4) diff += step
rjmp __1
add XL,R20
adc XH,R21
__1:
lsr R21 ; step >>= 1
ror R20
sbrs R22,1 ; if(value & 2) diff += step
rjmp __2
add XL,R20
adc XH,R21
__2:
lsr R21 ; step >>= 1
ror R20
sbrs R22,0 ; if(value & 1) diff += step
rjmp __3
add XL,R20
adc XH,R21
__3:
lsr R21 ; step >>= 1
ror R20
add XL,R20 ; diff += step
adc XH,R21
; update sample
ldi R21,0x80
add R19,R21 ; sample += 0x8000
sbrs R22,3 ; if(value & 7)
rjmp __4
sub R18,XL ; sample -= diff
sbc R19,XH
brcc __5
clr R18 ; if(sample < 0) sample = 0
clr R19
rjmp __5
__4: ; else
add R18,XL ; sample += diff
adc R19,XH
brcc __5
ser R18 ; if(sample > 0xffff) sample = 0xffff
ser R19
__5:
sub R19,R21 ; sample -= 0x8000
; update index
ldi ZL, lo8(index_table)
ldi ZH, hi8(index_table)
andi R22,7 ; value &= 7
add ZL,R22
adc ZH,R1
lpm R20,Z
add R23,R20 ; index += index_table[value]
brpl __6 ; if(index < 0)
clr R23 ; index = 0
rjmp __7
__6:
cpi R23,89 ; if(index >= 89)
brlo __7
ldi R23,88 ; index = 88
__7:
movw XL,R24
st X+,R18
st X+,R19
st X,R23
ret
; ------------------------------------------------------------------------------
index_table:
.byte -1, -1, -1, -1, 2, 4, 6, 8
; ------------------------------------------------------------------------------
step_table:
.word 7, 8, 9, 10, 11, 12, 13, 14
.word 16, 17, 19, 21, 23, 25, 28, 31
.word 34, 37, 41, 45, 50, 55, 60, 66
.word 73, 80, 88, 97, 107, 118, 130, 143
.word 157, 173, 190, 209, 230, 253, 279, 307
.word 337, 371, 408, 449, 494, 544, 598, 658
.word 724, 796, 876, 963, 1060, 1166, 1282, 1411
.word 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024
.word 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484
.word 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899
.word 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794
.word 32767
; ------------------------------------------------------------------------------
void playima(char *name)snd_freq устанавливает частоту загрузки данных из кольцевого буфера в регистр PWM
{
uint8_t buff[512];
WORD cb;
uint16_t n;
ima_state state[2];
uint8_t data;
if(!pf_open(name))
{
snd_freq(44100);
state[0].sample = 0;
state[0].index = 0;
state[1].sample = 0;
state[1].index = 0;
while(!pf_read(buff, sizeof(buff), &cb))
{
for(n = 0; n < cb; ++n)
{
data = buff[n];
imadec(state+0, data);
imadec(state+1, data>>4);
snd_out( (state[0].sample>>8)+0x80, (state[1].sample>>8)+0x80 );
}
if(cb != sizeof(buff))
break;
}
}
}
snd_out кладет данные в кольцевой буфер
А здесь можно скачать прогу для перекодирования WAV файлов в IMA и пример прошивки, воспроизводящей файл, сжатый IMA с SD-карточки.
зы. Данный кодек я очень люблю, и юзаю как в девайсах на МК, так и в прогах для компа, для передачи звука по сети (в этом случае можно сверху ещё deflate'ом прижать).
-------------------------------------------------------------------------------------------------------------------------
Комментарии
Отправить комментарий