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:
bnnm 2021-02-21 22:15:56 +01:00 committed by GitHub
commit b3c50be513
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 119 additions and 80 deletions

View File

@ -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;
}
}

View File

@ -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 */

View File

@ -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;

View File

@ -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);

View File

@ -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)
};

View File

@ -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) */

View File

@ -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);

View File

@ -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;

View File

@ -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;
{

View File

@ -1,3 +1,4 @@
#include <math.h>
#include "meta.h"
#include "../layout/layout.h"
#include "../coding/coding.h"