mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-02-20 20:41:08 +01:00
Merge pull request #816 from bnnm/tac3-adx
- Adjust tri-Ace codec issues - Add scramble key for .awb w/ ADX [Assault Lily Last Bullet (Android)] - Add encrypted Ogg [Adventure Field 4 (PC)]
This commit is contained in:
commit
b3c50be513
@ -12,7 +12,7 @@ struct tac_codec_data {
|
||||
int encoder_delay;
|
||||
|
||||
uint8_t buf[TAC_BLOCK_SIZE];
|
||||
int read_block;
|
||||
int feed_block;
|
||||
off_t offset;
|
||||
|
||||
int16_t* samples;
|
||||
@ -38,7 +38,7 @@ tac_codec_data* init_tac(STREAMFILE* sf) {
|
||||
data->handle = tac_init(data->buf, bytes);
|
||||
if (!data->handle) goto fail;
|
||||
|
||||
data->read_block = 0; /* ok to use current block */
|
||||
data->feed_block = 0; /* ok to use current block */
|
||||
data->offset = bytes;
|
||||
data->channels = TAC_CHANNELS;
|
||||
data->frame_samples = TAC_FRAME_SAMPLES;
|
||||
@ -66,15 +66,17 @@ static int decode_frame(tac_codec_data* data) {
|
||||
err = tac_decode_frame(data->handle, data->buf);
|
||||
|
||||
if (err == TAC_PROCESS_NEXT_BLOCK) {
|
||||
data->read_block = 1;
|
||||
data->feed_block = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (err == TAC_PROCESS_DONE) {
|
||||
VGM_LOG("TAC: process done (EOF) %i\n", err);
|
||||
goto fail; /* shouldn't reach this */
|
||||
}
|
||||
|
||||
if (err != TAC_PROCESS_OK) {
|
||||
VGM_LOG("TAC: process error %i\n", err);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@ -90,10 +92,10 @@ fail:
|
||||
static int read_frame(tac_codec_data* data, STREAMFILE* sf) {
|
||||
|
||||
/* new block must be read only when signaled by lib */
|
||||
if (data->read_block) {
|
||||
if (data->feed_block) {
|
||||
int bytes = read_streamfile(data->buf, data->offset, sizeof(data->buf), sf);
|
||||
data->offset += bytes;
|
||||
data->read_block = 0;
|
||||
data->feed_block = 0;
|
||||
if (bytes <= 0) goto fail; /* can read less that buf near EOF */
|
||||
}
|
||||
|
||||
@ -139,7 +141,8 @@ void reset_tac(tac_codec_data* data) {
|
||||
|
||||
tac_reset(data->handle);
|
||||
|
||||
data->read_block = 1;
|
||||
data->offset = 0;
|
||||
data->feed_block = 1;
|
||||
data->sbuf.filled = 0;
|
||||
data->samples_discard = data->encoder_delay;
|
||||
|
||||
@ -149,20 +152,19 @@ void reset_tac(tac_codec_data* data) {
|
||||
void seek_tac(tac_codec_data* data, int32_t num_sample) {
|
||||
int32_t loop_sample;
|
||||
const tac_header_t* hdr;
|
||||
|
||||
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
hdr = tac_get_header(data->handle);
|
||||
|
||||
loop_sample = hdr->loop_frame * TAC_FRAME_SAMPLES + hdr->loop_discard;
|
||||
loop_sample = (hdr->loop_frame - 1) * TAC_FRAME_SAMPLES + hdr->loop_discard;
|
||||
if (loop_sample == num_sample) {
|
||||
/* simulates original looping (that wouldn't clean codec internals) */
|
||||
tac_set_loop(data->handle);
|
||||
tac_set_loop(data->handle); /* direct looping */
|
||||
|
||||
data->samples_discard = hdr->loop_discard;
|
||||
data->offset = hdr->loop_offset;
|
||||
data->read_block = 1;
|
||||
data->feed_block = 1;
|
||||
data->sbuf.filled = 0;
|
||||
}
|
||||
else {
|
||||
@ -170,7 +172,7 @@ void seek_tac(tac_codec_data* data, int32_t num_sample) {
|
||||
|
||||
data->samples_discard = num_sample;
|
||||
data->offset = 0;
|
||||
data->read_block = 1;
|
||||
data->feed_block = 1;
|
||||
data->sbuf.filled = 0;
|
||||
}
|
||||
}
|
||||
|
@ -16,8 +16,8 @@
|
||||
* container?) and handler lib may be "Csd". Looks inspired by MPEG (much simplified) with bits
|
||||
* from other codecs (per-file codebook and 1024 samples).
|
||||
*
|
||||
* Original decoder is implemented in the PS2's VU1, a coprocessor specialized in vector/SIMD and
|
||||
* parallel instructions. As VU1 works with many 128 bit registers (typically x4 floats) algorithm
|
||||
* Original decoder is mainly implemented in the PS2's VU1, a coprocessor specialized in vector/SIMD
|
||||
* and parallel instructions. As VU1 works with many 128 bit registers (typically x4 floats) algorithm
|
||||
* was tailored to do multiple ops at once. This code tries to simplify it into standard C to a point,
|
||||
* but keeps this vector style in main decoding to ease porting (since tables are made with SIMD in
|
||||
* mind it would need some transposing around) and for PS2 float simulation.
|
||||
@ -1053,7 +1053,7 @@ static int init_header(tac_header_t* header, const uint8_t* buf) {
|
||||
/* header size ia block-aligned (but actual size can be smaller, ex. VP 00000715) */
|
||||
if (header->file_size % TAC_BLOCK_SIZE != 0)
|
||||
return TAC_PROCESS_HEADER_ERROR;
|
||||
/* assumed but should be ok */
|
||||
/* loop_discard over max makes game crash, while frame_discard seems to ignore it */
|
||||
if (header->loop_discard > TAC_FRAME_SAMPLES || header->frame_discard > TAC_FRAME_SAMPLES)
|
||||
return TAC_PROCESS_HEADER_ERROR;
|
||||
/* looping makes sense */
|
||||
|
@ -24,15 +24,15 @@ typedef struct tac_handle_t tac_handle_t;
|
||||
typedef struct {
|
||||
/* 0x20 header config */
|
||||
uint32_t huffman_offset; /* setup */
|
||||
uint32_t unknown; /* ignored? may be CDVD stuff (divided/multiplied during PS2 process), not file size related */
|
||||
uint16_t loop_frame; /* aligned to block stard */
|
||||
uint16_t loop_discard; /* assumed */
|
||||
uint16_t frame_count; /* number of valid frames ("block end" frame not included) */
|
||||
uint16_t frame_discard; /* assumed */
|
||||
uint32_t loop_offset; /* file size if not looped */
|
||||
uint32_t file_size; /* actual file size can be a bit smaller if last block is truncated */
|
||||
uint32_t unknown; /* ignored? (may be CDVD stuff, divided/multiplied during PS2 process, not size related) */
|
||||
uint16_t loop_frame; /* aligned to block start */
|
||||
uint16_t loop_discard; /* discarded start samples in loop frame (lower = outputs more) */
|
||||
uint16_t frame_count; /* number of valid frames ("block end" frames not included) */
|
||||
uint16_t frame_discard; /* discarded end samples in final frame (lower = outputs less), even for non-looped files */
|
||||
uint32_t loop_offset; /* points to a block; file size if not looped */
|
||||
uint32_t file_size; /* block aligned; actual file size can be a bit smaller if last block is truncated */
|
||||
uint32_t joint_stereo; /* usually 0 and rarely 1 */
|
||||
uint32_t empty; /* null? */
|
||||
uint32_t empty; /* always null */
|
||||
} tac_header_t;
|
||||
|
||||
|
||||
|
@ -11,11 +11,15 @@
|
||||
#define ADX_KEY_MAX_TEST_FRAMES 32768
|
||||
#define ADX_KEY_TEST_BUFFER_SIZE 0x8000
|
||||
|
||||
static int find_adx_key(STREAMFILE *sf, uint8_t type, uint16_t *xor_start, uint16_t *xor_mult, uint16_t *xor_add);
|
||||
static int find_adx_key(STREAMFILE *sf, uint8_t type, uint16_t *xor_start, uint16_t *xor_mult, uint16_t *xor_add, uint16_t subkey);
|
||||
|
||||
VGMSTREAM* init_vgmstream_adx(STREAMFILE* sf) {
|
||||
return init_vgmstream_adx_subkey(sf, 0);
|
||||
}
|
||||
|
||||
/* ADX - CRI Middleware format */
|
||||
VGMSTREAM * init_vgmstream_adx(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
VGMSTREAM* init_vgmstream_adx_subkey(STREAMFILE* sf, uint16_t subkey) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
off_t start_offset, hist_offset = 0;
|
||||
int loop_flag = 0, channel_count;
|
||||
int32_t loop_start_sample = 0, loop_end_sample = 0;
|
||||
@ -32,18 +36,18 @@ VGMSTREAM * init_vgmstream_adx(STREAMFILE *streamFile) {
|
||||
/* checks*/
|
||||
/* .adx: standard
|
||||
* .adp: Headhunter (DC) */
|
||||
if (!check_extensions(streamFile,"adx,adp"))
|
||||
if (!check_extensions(sf,"adx,adp"))
|
||||
goto fail;
|
||||
|
||||
if ((uint16_t)read_16bitBE(0x00,streamFile) != 0x8000)
|
||||
if (read_u16be(0x00,sf) != 0x8000)
|
||||
goto fail;
|
||||
|
||||
start_offset = (uint16_t)read_16bitBE(0x02,streamFile) + 0x04;
|
||||
if ((uint16_t)read_16bitBE(start_offset - 0x06,streamFile) != 0x2863 || /* "(c" */
|
||||
(uint32_t)read_32bitBE(start_offset - 0x04,streamFile) != 0x29435249) /* ")CRI" */
|
||||
start_offset = read_u16be(0x02,sf) + 0x04;
|
||||
if (read_u16be(start_offset - 0x06,sf) != 0x2863 || /* "(c" */
|
||||
read_u32be(start_offset - 0x04,sf) != 0x29435249) /* ")CRI" */
|
||||
goto fail;
|
||||
|
||||
encoding_type = read_8bit(0x04, streamFile);
|
||||
encoding_type = read_u8(0x04, sf);
|
||||
switch (encoding_type) {
|
||||
case 0x02:
|
||||
coding_type = coding_CRI_ADX_fixed;
|
||||
@ -60,29 +64,29 @@ VGMSTREAM * init_vgmstream_adx(STREAMFILE *streamFile) {
|
||||
|
||||
/* ADX encoders can't set this value, but is honored by ADXPlay if changed and multiple of 0x12,
|
||||
* though output is unusual and may not be fully supported (works in mono so not an interleave) */
|
||||
frame_size = read_8bit(0x05, streamFile);
|
||||
frame_size = read_8bit(0x05, sf);
|
||||
|
||||
if (read_8bit(0x06,streamFile) != 4) /* bits per sample */
|
||||
if (read_u8(0x06,sf) != 4) /* bits per sample */
|
||||
goto fail;
|
||||
|
||||
/* older ADX (adxencd) up to 2ch, newer ADX (criatomencd) up to 8 */
|
||||
channel_count = read_8bit(0x07,streamFile);
|
||||
channel_count = read_u8(0x07,sf);
|
||||
/* 0x08: sample rate */
|
||||
/* 0x0c: samples */
|
||||
/* 0x10: high-pass frequency */
|
||||
|
||||
version = read_16bitBE(0x12,streamFile);
|
||||
version = read_u16be(0x12,sf);
|
||||
|
||||
/* encryption */
|
||||
if (version == 0x0408) {
|
||||
if (find_adx_key(streamFile, 8, &xor_start, &xor_mult, &xor_add)) {
|
||||
if (find_adx_key(sf, 8, &xor_start, &xor_mult, &xor_add, 0)) {
|
||||
coding_type = coding_CRI_ADX_enc_8;
|
||||
version = 0x0400;
|
||||
}
|
||||
VGM_ASSERT(version != 0x0400, "ADX: keystring not found\n");
|
||||
}
|
||||
else if (version == 0x0409) {
|
||||
if (find_adx_key(streamFile, 9, &xor_start, &xor_mult, &xor_add)) {
|
||||
if (find_adx_key(sf, 9, &xor_start, &xor_mult, &xor_add, subkey)) {
|
||||
coding_type = coding_CRI_ADX_enc_9;
|
||||
version = 0x0400;
|
||||
}
|
||||
@ -103,11 +107,11 @@ VGMSTREAM * init_vgmstream_adx(STREAMFILE *streamFile) {
|
||||
/* 0x00 (2): initial loop padding (the encoder adds a few blank samples so loop start is block-aligned; max 31)
|
||||
* ex. loop_start=12: enc_start=32, padding=20 (32-20=12); loop_start=35: enc_start=64, padding=29 (64-29=35)
|
||||
* 0x02 (2): loop sample(?) flag (always 1) */
|
||||
loop_flag = read_32bitBE(loops_offset+0x04,streamFile) != 0; /* loop offset(?) flag (always 1) */
|
||||
loop_start_sample = read_32bitBE(loops_offset+0x08,streamFile);
|
||||
//loop_start_offset = read_32bitBE(loops_offset+0x0c,streamFile);
|
||||
loop_end_sample = read_32bitBE(loops_offset+0x10,streamFile);
|
||||
//loop_end_offset = read_32bitBE(loops_offset+0x14,streamFile);
|
||||
loop_flag = read_32bitBE(loops_offset+0x04,sf) != 0; /* loop offset(?) flag (always 1) */
|
||||
loop_start_sample = read_32bitBE(loops_offset+0x08,sf);
|
||||
//loop_start_offset = read_32bitBE(loops_offset+0x0c,sf);
|
||||
loop_end_sample = read_32bitBE(loops_offset+0x10,sf);
|
||||
//loop_end_offset = read_32bitBE(loops_offset+0x14,sf);
|
||||
}
|
||||
}
|
||||
else if (version == 0x0400) { /* common */
|
||||
@ -120,8 +124,8 @@ VGMSTREAM * init_vgmstream_adx(STREAMFILE *streamFile) {
|
||||
hist_size = (channel_count > 1 ? 0x04 * channel_count : 0x04 + 0x04); /* min is 8, even in 1ch files */
|
||||
|
||||
ainf_offset = base_size + hist_size + 0x04; /* not seen with >2ch though */
|
||||
if ((uint32_t)read_32bitBE(ainf_offset+0x00,streamFile) == 0x41494E46) /* "AINF" */
|
||||
ainf_size = read_32bitBE(ainf_offset+0x04,streamFile);
|
||||
if (read_u32be(ainf_offset+0x00,sf) == 0x41494E46) /* "AINF" */
|
||||
ainf_size = read_32bitBE(ainf_offset+0x04,sf);
|
||||
|
||||
if (start_offset - ainf_size - 0x06 >= hist_offset + hist_size + loops_size) { /* enough space for loop info? */
|
||||
off_t loops_offset = base_size + hist_size;
|
||||
@ -129,11 +133,11 @@ VGMSTREAM * init_vgmstream_adx(STREAMFILE *streamFile) {
|
||||
/* 0x00 (2): initial loop padding (the encoder adds a few blank samples so loop start is block-aligned; max 31)
|
||||
* ex. loop_start=12: enc_start=32, padding=20 (32-20=12); loop_start=35: enc_start=64, padding=29 (64-29=35)
|
||||
* 0x02 (2): loop sample(?) flag (always 1) */
|
||||
loop_flag = read_32bitBE(loops_offset+0x04,streamFile) != 0; /* loop offset(?) flag (always 1) */
|
||||
loop_start_sample = read_32bitBE(loops_offset+0x08,streamFile);
|
||||
//loop_start_offset = read_32bitBE(loops_offset+0x0c,streamFile);
|
||||
loop_end_sample = read_32bitBE(loops_offset+0x10,streamFile);
|
||||
//loop_end_offset = read_32bitBE(loops_offset+0x14,streamFile);
|
||||
loop_flag = read_32bitBE(loops_offset+0x04,sf) != 0; /* loop offset(?) flag (always 1) */
|
||||
loop_start_sample = read_32bitBE(loops_offset+0x08,sf);
|
||||
//loop_start_offset = read_32bitBE(loops_offset+0x0c,sf);
|
||||
loop_end_sample = read_32bitBE(loops_offset+0x10,sf);
|
||||
//loop_end_offset = read_32bitBE(loops_offset+0x14,sf);
|
||||
}
|
||||
|
||||
/* AINF header info (may be inserted by CRI's tools but is rarely used)
|
||||
@ -165,8 +169,8 @@ VGMSTREAM * init_vgmstream_adx(STREAMFILE *streamFile) {
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = read_32bitBE(0x08,streamFile);
|
||||
vgmstream->num_samples = read_32bitBE(0x0c,streamFile);
|
||||
vgmstream->sample_rate = read_32bitBE(0x08,sf);
|
||||
vgmstream->num_samples = read_32bitBE(0x0c,sf);
|
||||
vgmstream->loop_start_sample = loop_start_sample;
|
||||
vgmstream->loop_end_sample = loop_end_sample;
|
||||
|
||||
@ -195,7 +199,7 @@ VGMSTREAM * init_vgmstream_adx(STREAMFILE *streamFile) {
|
||||
double x,y,z,a,b,c;
|
||||
int i;
|
||||
/* high-pass cutoff frequency, always 500 that I've seen */
|
||||
uint16_t cutoff = (uint16_t)read_16bitBE(0x10,streamFile);
|
||||
uint16_t cutoff = read_u16be(0x10,sf);
|
||||
|
||||
x = cutoff;
|
||||
y = vgmstream->sample_rate;
|
||||
@ -222,8 +226,8 @@ VGMSTREAM * init_vgmstream_adx(STREAMFILE *streamFile) {
|
||||
/* 2 hist shorts per ch, corresponding to the very first original sample repeated (verified with CRI's encoders).
|
||||
* Not vital as their effect is small, after a few samples they don't matter, and most songs start in silence. */
|
||||
if (hist_offset) {
|
||||
vgmstream->ch[i].adpcm_history1_32 = read_16bitBE(hist_offset + i*4 + 0x00,streamFile);
|
||||
vgmstream->ch[i].adpcm_history2_32 = read_16bitBE(hist_offset + i*4 + 0x02,streamFile);
|
||||
vgmstream->ch[i].adpcm_history1_32 = read_16bitBE(hist_offset + i*4 + 0x00,sf);
|
||||
vgmstream->ch[i].adpcm_history2_32 = read_16bitBE(hist_offset + i*4 + 0x02,sf);
|
||||
}
|
||||
|
||||
if (coding_type == coding_CRI_ADX_enc_8 || coding_type == coding_CRI_ADX_enc_9) {
|
||||
@ -240,7 +244,7 @@ VGMSTREAM * init_vgmstream_adx(STREAMFILE *streamFile) {
|
||||
}
|
||||
|
||||
|
||||
if ( !vgmstream_open_stream(vgmstream,streamFile,start_offset) )
|
||||
if ( !vgmstream_open_stream(vgmstream, sf, start_offset) )
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
@ -252,7 +256,7 @@ fail:
|
||||
|
||||
/* ADX key detection works by reading XORed ADPCM scales in frames, and un-XORing with keys in
|
||||
* a list. If resulting values are within the expected range for N scales we accept that key. */
|
||||
static int find_adx_key(STREAMFILE *sf, uint8_t type, uint16_t *xor_start, uint16_t *xor_mult, uint16_t *xor_add) {
|
||||
static int find_adx_key(STREAMFILE* sf, uint8_t type, uint16_t *xor_start, uint16_t *xor_mult, uint16_t *xor_add, uint16_t subkey) {
|
||||
const int frame_size = 0x12;
|
||||
uint16_t *scales = NULL;
|
||||
uint16_t *prescales = NULL;
|
||||
@ -295,7 +299,17 @@ static int find_adx_key(STREAMFILE *sf, uint8_t type, uint16_t *xor_start, uint1
|
||||
return 1;
|
||||
}
|
||||
else if (type == 9 && key_size == 0x08) {
|
||||
uint64_t keycode = (uint64_t)get_64bitBE(keybuf);
|
||||
uint64_t keycode = get_u64be(keybuf);
|
||||
if (subkey) {
|
||||
keycode = keycode * ( ((uint64_t)subkey << 16u) | ((uint16_t)~subkey + 2u) );
|
||||
}
|
||||
derive_adx_key9(keycode, xor_start, xor_mult, xor_add);
|
||||
return 1;
|
||||
}
|
||||
else if (type == 9 && key_size == 0x08+0x02) {
|
||||
uint64_t file_key = get_u64be(keybuf+0x00);
|
||||
uint16_t file_sub = get_u16be(keybuf+0x08);
|
||||
uint64_t keycode = file_key * ( ((uint64_t)file_sub << 16u) | ((uint16_t)~file_sub + 2u) );
|
||||
derive_adx_key9(keycode, xor_start, xor_mult, xor_add);
|
||||
return 1;
|
||||
}
|
||||
@ -414,7 +428,11 @@ static int find_adx_key(STREAMFILE *sf, uint8_t type, uint16_t *xor_start, uint1
|
||||
derive_adx_key8(keys[key_id].key8, &key_xor, &key_mul, &key_add);
|
||||
}
|
||||
else if (type == 9 && keys[key_id].key9) {
|
||||
derive_adx_key9(keys[key_id].key9, &key_xor, &key_mul, &key_add);
|
||||
uint64_t keycode = keys[key_id].key9;
|
||||
if (subkey) {
|
||||
keycode = keycode * ( ((uint64_t)subkey << 16u) | ((uint16_t)~subkey + 2u) );
|
||||
}
|
||||
derive_adx_key9(keycode, &key_xor, &key_mul, &key_add);
|
||||
}
|
||||
else {
|
||||
VGM_LOG("ADX: incorrectly defined key id=%i\n", key_id);
|
||||
|
@ -244,7 +244,7 @@ static const adxkey_info adxkey9_list[] = {
|
||||
{0x0000,0x1c85,0x7043, NULL,29915170}, // 0000000001C87822
|
||||
|
||||
/* Assault Lily Last Bullet (Android) */
|
||||
{0x0aca,0x0ef5,0x05c9, NULL,0}, // guessed with VGAudio (possible key: 5650EF42E5 / 370725044965)
|
||||
{0x0000,0x0000,0x0000, NULL,6349046567469313}, // 00168E6C99510101 (+ AWB subkeys)
|
||||
|
||||
};
|
||||
|
||||
|
@ -135,7 +135,7 @@ VGMSTREAM* init_vgmstream_awb_memory(STREAMFILE* sf, STREAMFILE* sf_acb) {
|
||||
if (!vgmstream) goto fail;
|
||||
break;
|
||||
case ADX: /* Okami HD (PS4) */
|
||||
vgmstream = init_vgmstream_adx(temp_sf);
|
||||
vgmstream = init_vgmstream_adx_subkey(temp_sf, subkey);
|
||||
if (!vgmstream) goto fail;
|
||||
break;
|
||||
case VAG: /* Ukiyo no Roushi (Vita) */
|
||||
|
@ -6,7 +6,8 @@
|
||||
VGMSTREAM* init_vgmstream_silence(int channels, int sample_rate, int32_t num_samples);
|
||||
|
||||
|
||||
VGMSTREAM * init_vgmstream_adx(STREAMFILE *streamFile);
|
||||
VGMSTREAM* init_vgmstream_adx(STREAMFILE* sf);
|
||||
VGMSTREAM* init_vgmstream_adx_subkey(STREAMFILE* sf, uint16_t subkey);
|
||||
|
||||
VGMSTREAM * init_vgmstream_afc(STREAMFILE *streamFile);
|
||||
|
||||
|
@ -82,6 +82,20 @@ static void rpgmvo_ogg_decryption_callback(void* ptr, size_t size, size_t nmemb,
|
||||
}
|
||||
}
|
||||
|
||||
static void at4_ogg_decryption_callback(void* ptr, size_t size, size_t nmemb, void* datasource) {
|
||||
static const uint8_t af4_key[0x10] = {
|
||||
0x00,0x0E,0x08,0x1E, 0x18,0x37,0x12,0x00, 0x48,0x87,0x46,0x0B, 0x9C,0x68,0xA8,0x4B
|
||||
};
|
||||
uint8_t *ptr8 = ptr;
|
||||
size_t bytes_read = size * nmemb;
|
||||
ogg_vorbis_io *io = datasource;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < bytes_read; i++) {
|
||||
ptr8[i] -= af4_key[(io->offset + i) % sizeof(af4_key)];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static const uint32_t xiph_mappings[] = {
|
||||
0,
|
||||
@ -152,31 +166,34 @@ VGMSTREAM* init_vgmstream_ogg_vorbis(STREAMFILE* sf) {
|
||||
}
|
||||
|
||||
if (is_ogg) {
|
||||
if (read_32bitBE(0x00,sf) == 0x2c444430) { /* Psychic Software [Darkwind: War on Wheels (PC)] */
|
||||
if (read_u32be(0x00,sf) == 0x2c444430) { /* Psychic Software [Darkwind: War on Wheels (PC)] */
|
||||
ovmi.decryption_callback = psychic_ogg_decryption_callback;
|
||||
}
|
||||
else if (read_32bitBE(0x00,sf) == 0x4C325344) { /* "L2SD" instead of "OggS" [Lineage II Chronicle 4 (PC)] */
|
||||
else if (read_u32be(0x00,sf) == 0x4C325344) { /* "L2SD" instead of "OggS" [Lineage II Chronicle 4 (PC)] */
|
||||
cfg.is_header_swap = 1;
|
||||
cfg.is_encrypted = 1;
|
||||
}
|
||||
else if (read_32bitBE(0x00,sf) == 0x048686C5) { /* "OggS" XOR'ed + bitswapped [Ys VIII (PC)] */
|
||||
else if (read_u32be(0x00,sf) == 0x048686C5) { /* "OggS" XOR'ed + bitswapped [Ys VIII (PC)] */
|
||||
cfg.key[0] = 0xF0;
|
||||
cfg.key_len = 1;
|
||||
cfg.is_nibble_swap = 1;
|
||||
cfg.is_encrypted = 1;
|
||||
|
||||
}
|
||||
else if (read_32bitBE(0x00,sf) == 0x00000000 && /* null instead of "OggS" [Yuppie Psycho (PC)] */
|
||||
read_32bitBE(0x3a,sf) == 0x4F676753) { /* "OggS" in next page */
|
||||
else if (read_u32be(0x00,sf) == 0x00000000 && /* null instead of "OggS" [Yuppie Psycho (PC)] */
|
||||
read_u32be(0x3a,sf) == 0x4F676753) { /* "OggS" in next page */
|
||||
cfg.is_header_swap = 1;
|
||||
cfg.is_encrypted = 1;
|
||||
}
|
||||
else if (read_32bitBE(0x00,sf) != 0x4F676753 && /* random(?) swap instead of "OggS" [Tobi Tsukihime (PC)] */
|
||||
read_32bitBE(0x3a,sf) == 0x4F676753) { /* "OggS" in next page */
|
||||
else if (read_u32be(0x00,sf) != 0x4F676753 && /* random(?) swap instead of "OggS" [Tobi Tsukihime (PC)] */
|
||||
read_u32be(0x3a,sf) == 0x4F676753) { /* "OggS" in next page */
|
||||
cfg.is_header_swap = 1;
|
||||
cfg.is_encrypted = 1;
|
||||
}
|
||||
else if (read_32bitBE(0x00,sf) == 0x4F676753) { /* "OggS" (standard) */
|
||||
else if (read_u32be(0x00,sf) == 0x4F756F71) { /* "OggS" encrypted [Adventure Field 4 (PC)]*/
|
||||
ovmi.decryption_callback = at4_ogg_decryption_callback;
|
||||
}
|
||||
else if (read_u32be(0x00,sf) == 0x4F676753) { /* "OggS" (standard) */
|
||||
;
|
||||
}
|
||||
else {
|
||||
@ -185,13 +202,13 @@ VGMSTREAM* init_vgmstream_ogg_vorbis(STREAMFILE* sf) {
|
||||
}
|
||||
|
||||
if (is_um3) { /* ["Ultramarine3" (???)] */
|
||||
if (read_32bitBE(0x00,sf) != 0x4f676753) { /* "OggS" (optionally encrypted) */
|
||||
if (read_u32be(0x00,sf) != 0x4f676753) { /* "OggS" (optionally encrypted) */
|
||||
ovmi.decryption_callback = um3_ogg_decryption_callback;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_kovs) { /* Koei Tecmo PC games */
|
||||
if (read_32bitBE(0x00,sf) != 0x4b4f5653) { /* "KOVS" */
|
||||
if (read_u32be(0x00,sf) != 0x4b4f5653) { /* "KOVS" */
|
||||
goto fail;
|
||||
}
|
||||
ovmi.loop_start = read_32bitLE(0x08,sf);
|
||||
@ -203,7 +220,7 @@ VGMSTREAM* init_vgmstream_ogg_vorbis(STREAMFILE* sf) {
|
||||
}
|
||||
|
||||
if (is_sngw) { /* [Capcom's MT Framework PC games] */
|
||||
if (read_32bitBE(0x00,sf) != 0x4f676753) { /* "OggS" (optionally encrypted) */
|
||||
if (read_u32be(0x00,sf) != 0x4f676753) { /* "OggS" (optionally encrypted) */
|
||||
cfg.key_len = read_streamfile(cfg.key, 0x00, 0x04, sf);
|
||||
cfg.is_header_swap = 1;
|
||||
cfg.is_nibble_swap = 1;
|
||||
@ -217,7 +234,7 @@ VGMSTREAM* init_vgmstream_ogg_vorbis(STREAMFILE* sf) {
|
||||
const char *isl_name = NULL;
|
||||
|
||||
/* check various encrypted "OggS" values */
|
||||
if (read_32bitBE(0x00,sf) == 0xAF678753) { /* Azure Striker Gunvolt (PC) */
|
||||
if (read_u32be(0x00,sf) == 0xAF678753) { /* Azure Striker Gunvolt (PC) */
|
||||
static const uint8_t isd_gv_key[16] = {
|
||||
0xe0,0x00,0xe0,0x00,0xa0,0x00,0x00,0x00,0xe0,0x00,0xe0,0x80,0x40,0x40,0x40,0x00
|
||||
};
|
||||
@ -225,7 +242,7 @@ VGMSTREAM* init_vgmstream_ogg_vorbis(STREAMFILE* sf) {
|
||||
memcpy(cfg.key, isd_gv_key, cfg.key_len);
|
||||
isl_name = "GV_steam.isl";
|
||||
}
|
||||
else if (read_32bitBE(0x00,sf) == 0x0FE787D3) { /* Mighty Gunvolt (PC) */
|
||||
else if (read_u32be(0x00,sf) == 0x0FE787D3) { /* Mighty Gunvolt (PC) */
|
||||
static const uint8_t isd_mgv_key[120] = {
|
||||
0x40,0x80,0xE0,0x80,0x40,0x40,0xA0,0x00,0xA0,0x40,0x00,0x80,0x00,0x40,0xA0,0x00,
|
||||
0xC0,0x40,0xE0,0x00,0x60,0x40,0x80,0x00,0xA0,0x00,0xE0,0x00,0x60,0x40,0xC0,0x00,
|
||||
@ -240,7 +257,7 @@ VGMSTREAM* init_vgmstream_ogg_vorbis(STREAMFILE* sf) {
|
||||
memcpy(cfg.key, isd_mgv_key, cfg.key_len);
|
||||
isl_name = "MGV_steam.isl";
|
||||
}
|
||||
else if (read_32bitBE(0x00,sf) == 0x0FA74753) { /* Blaster Master Zero (PC) */
|
||||
else if (read_u32be(0x00,sf) == 0x0FA74753) { /* Blaster Master Zero (PC) */
|
||||
static const uint8_t isd_bmz_key[120] = {
|
||||
0x40,0xC0,0x20,0x00,0x40,0xC0,0xC0,0x00,0x00,0x80,0xE0,0x80,0x80,0x40,0x20,0x00,
|
||||
0x60,0xC0,0xC0,0x00,0xA0,0x80,0x60,0x00,0x40,0x40,0x20,0x00,0x60,0x40,0xC0,0x00,
|
||||
@ -374,7 +391,7 @@ VGMSTREAM* init_vgmstream_ogg_vorbis(STREAMFILE* sf) {
|
||||
uint32_t xor_be;
|
||||
|
||||
put_32bitLE(key, (uint32_t)file_size);
|
||||
xor_be = (uint32_t)get_32bitBE(key);
|
||||
xor_be = get_u32be(key);
|
||||
if ((read_32bitBE(0x00,sf) ^ xor_be) == 0x4F676753) { /* "OggS" */
|
||||
int i;
|
||||
cfg.key_len = 4;
|
||||
|
@ -35,7 +35,7 @@ VGMSTREAM* init_vgmstream_tac(STREAMFILE* sf) {
|
||||
goto fail;
|
||||
|
||||
channel_count = 2; /* always stereo */
|
||||
loop_flag = (loop_offset != stream_size);
|
||||
loop_flag = (loop_offset != stream_size); /* actual check may be loop_frame > 0? */
|
||||
start_offset = 0;
|
||||
|
||||
|
||||
@ -45,8 +45,8 @@ VGMSTREAM* init_vgmstream_tac(STREAMFILE* sf) {
|
||||
|
||||
vgmstream->meta_type = meta_TAC;
|
||||
vgmstream->sample_rate = 48000;
|
||||
vgmstream->num_samples = frame_count * 1024 - frame_discard;
|
||||
vgmstream->loop_start_sample = loop_frame * 1024 + loop_discard;
|
||||
vgmstream->num_samples = frame_count * 1024 - (1024 - frame_discard);
|
||||
vgmstream->loop_start_sample = (loop_frame - 1) * 1024 + loop_discard;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
{
|
||||
|
@ -1,3 +1,4 @@
|
||||
#include <math.h>
|
||||
#include "meta.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "../coding/coding.h"
|
||||
|
Loading…
x
Reference in New Issue
Block a user