mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-14 10:37:38 +01:00
Merge pull request #1592 from EdnessP/master
Sony BNK: 0x23 codec fixes and ZLSD support
This commit is contained in:
commit
61b84a683e
@ -3,7 +3,7 @@
|
|||||||
#include "../coding/coding.h"
|
#include "../coding/coding.h"
|
||||||
#include "../util/endianness.h"
|
#include "../util/endianness.h"
|
||||||
|
|
||||||
typedef enum { NONE, DUMMY, PSX, PCM16, MPEG, ATRAC9, HEVAG, RIFF_ATRAC9 } bnk_codec;
|
typedef enum { NONE, DUMMY, EXTERNAL, PSX, PCM16, MPEG, ATRAC9, HEVAG, RIFF_ATRAC9, XVAG_ATRAC9 } bnk_codec;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bnk_codec codec;
|
bnk_codec codec;
|
||||||
@ -47,9 +47,6 @@ typedef struct {
|
|||||||
|
|
||||||
uint32_t start_offset;
|
uint32_t start_offset;
|
||||||
uint32_t stream_offset;
|
uint32_t stream_offset;
|
||||||
uint32_t bank_name_offset;
|
|
||||||
uint32_t stream_name_offset;
|
|
||||||
uint32_t stream_name_size;
|
|
||||||
|
|
||||||
uint32_t stream_size;
|
uint32_t stream_size;
|
||||||
uint32_t interleave;
|
uint32_t interleave;
|
||||||
@ -69,10 +66,10 @@ VGMSTREAM* init_vgmstream_bnk_sony(STREAMFILE* sf) {
|
|||||||
bnk_header_t h = {0};
|
bnk_header_t h = {0};
|
||||||
|
|
||||||
/* checks */
|
/* checks */
|
||||||
if (!parse_bnk_v3(sf, &h))
|
|
||||||
return NULL;
|
|
||||||
if (!check_extensions(sf, "bnk"))
|
if (!check_extensions(sf, "bnk"))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
if (!parse_bnk_v3(sf, &h))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
|
||||||
/* build the VGMSTREAM */
|
/* build the VGMSTREAM */
|
||||||
@ -85,15 +82,6 @@ VGMSTREAM* init_vgmstream_bnk_sony(STREAMFILE* sf) {
|
|||||||
|
|
||||||
vgmstream->meta_type = meta_BNK_SONY;
|
vgmstream->meta_type = meta_BNK_SONY;
|
||||||
|
|
||||||
if (h.stream_name_size >= STREAM_NAME_SIZE || h.stream_name_size <= 0)
|
|
||||||
h.stream_name_size = STREAM_NAME_SIZE;
|
|
||||||
|
|
||||||
/* replace this with reading into the buffer ASAP when processing tables? */
|
|
||||||
if (h.bank_name_offset)
|
|
||||||
read_string(h.bank_name, h.stream_name_size, h.bank_name_offset, sf);
|
|
||||||
if (h.stream_name_offset)
|
|
||||||
read_string(h.stream_name, h.stream_name_size, h.stream_name_offset, sf);
|
|
||||||
|
|
||||||
if (h.stream_name[0]) {
|
if (h.stream_name[0]) {
|
||||||
get_streamfile_basename(sf, file_name, STREAM_NAME_SIZE);
|
get_streamfile_basename(sf, file_name, STREAM_NAME_SIZE);
|
||||||
if (h.bank_name[0] && strcmp(file_name, h.bank_name) != 0)
|
if (h.bank_name[0] && strcmp(file_name, h.bank_name) != 0)
|
||||||
@ -115,6 +103,39 @@ VGMSTREAM* init_vgmstream_bnk_sony(STREAMFILE* sf) {
|
|||||||
return temp_vs;
|
return temp_vs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case EXTERNAL: {
|
||||||
|
VGMSTREAM* temp_vs = NULL;
|
||||||
|
STREAMFILE* temp_sf = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
/* try with both stream_name and bank_name/stream_name? */
|
||||||
|
temp_sf = open_streamfile_by_filename(sf, h.stream_name);
|
||||||
|
if (!temp_sf) { /* create dummy stream if it can't be found */
|
||||||
|
temp_vs = init_vgmstream_silence_container(h.total_subsongs);
|
||||||
|
if (!temp_vs) goto fail;
|
||||||
|
|
||||||
|
temp_vs->meta_type = vgmstream->meta_type;
|
||||||
|
snprintf(temp_vs->stream_name, STREAM_NAME_SIZE, "%s [not found]", vgmstream->stream_name);
|
||||||
|
|
||||||
|
close_vgmstream(vgmstream);
|
||||||
|
return temp_vs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* are external streams always xvag? it shouldn't be hardcoded like this, but... */
|
||||||
|
/* and at that point does this also need to be put behind #ifdef VGM_USE_ATRAC9? */
|
||||||
|
/* known BNK v12 externals use XVAG MPEG but it functions differently in general */
|
||||||
|
temp_vs = init_vgmstream_xvag(temp_sf);
|
||||||
|
close_streamfile(temp_sf);
|
||||||
|
if (!temp_vs) goto fail;
|
||||||
|
|
||||||
|
temp_vs->num_streams = vgmstream->num_streams;
|
||||||
|
temp_vs->meta_type = vgmstream->meta_type;
|
||||||
|
strcpy(temp_vs->stream_name, vgmstream->stream_name);
|
||||||
|
|
||||||
|
close_vgmstream(vgmstream);
|
||||||
|
return temp_vs;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef VGM_USE_ATRAC9
|
#ifdef VGM_USE_ATRAC9
|
||||||
case ATRAC9: {
|
case ATRAC9: {
|
||||||
atrac9_config cfg = {0};
|
atrac9_config cfg = {0};
|
||||||
@ -154,6 +175,30 @@ VGMSTREAM* init_vgmstream_bnk_sony(STREAMFILE* sf) {
|
|||||||
close_vgmstream(vgmstream);
|
close_vgmstream(vgmstream);
|
||||||
return temp_vs;
|
return temp_vs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case XVAG_ATRAC9: {
|
||||||
|
VGMSTREAM* temp_vs = NULL;
|
||||||
|
STREAMFILE* temp_sf = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
temp_sf = setup_subfile_streamfile(sf, h.start_offset, h.stream_size, "xvag");
|
||||||
|
if (!temp_sf) goto fail;
|
||||||
|
temp_sf->stream_index = 1;
|
||||||
|
|
||||||
|
temp_vs = init_vgmstream_xvag(temp_sf);
|
||||||
|
close_streamfile(temp_sf);
|
||||||
|
if (!temp_vs) goto fail;
|
||||||
|
|
||||||
|
/* maybe also a separate warning/fail if XVAG returns more than 1 subsong? */
|
||||||
|
|
||||||
|
temp_vs->num_streams = vgmstream->num_streams;
|
||||||
|
//temp_vs->stream_size = vgmstream->stream_size;
|
||||||
|
temp_vs->meta_type = vgmstream->meta_type;
|
||||||
|
strcpy(temp_vs->stream_name, vgmstream->stream_name);
|
||||||
|
|
||||||
|
close_vgmstream(vgmstream);
|
||||||
|
return temp_vs;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef VGM_USE_MPEG
|
#ifdef VGM_USE_MPEG
|
||||||
case MPEG: {
|
case MPEG: {
|
||||||
@ -396,9 +441,10 @@ static bool process_tables(STREAMFILE* sf, bnk_header_t* h) {
|
|||||||
h->table2_suboffset = 0x00;
|
h->table2_suboffset = 0x00;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* later version have a few more tables (some optional) and work slightly differently (header is part of wave) */
|
/* later versions have a few more tables (some optional) and work slightly differently (header is part of wave) */
|
||||||
case 0x1a: /* Demon's Souls (PS5) */
|
case 0x1a: /* Demon's Souls (PS5) */
|
||||||
case 0x23: { /* The Last of Us (PC) */
|
case 0x23: { /* The Last of Us (PC) */
|
||||||
|
uint32_t bank_name_offset = h->sblk_offset + (h->sblk_version <= 0x1a ? 0x1c : 0x20);
|
||||||
uint32_t tables_offset = h->sblk_offset + (h->sblk_version <= 0x1a ? 0x120 : 0x128);
|
uint32_t tables_offset = h->sblk_offset + (h->sblk_version <= 0x1a ? 0x120 : 0x128);
|
||||||
uint32_t counts_offset = tables_offset + (h->sblk_version <= 0x1a ? 0x98 : 0xb0);
|
uint32_t counts_offset = tables_offset + (h->sblk_version <= 0x1a ? 0x98 : 0xb0);
|
||||||
|
|
||||||
@ -408,6 +454,8 @@ static bool process_tables(STREAMFILE* sf, bnk_header_t* h) {
|
|||||||
//h->sounds_entries = read_u16(counts_offset+0x00,sf);
|
//h->sounds_entries = read_u16(counts_offset+0x00,sf);
|
||||||
//h->grains_entries = read_u16(counts_offset+0x02,sf);
|
//h->grains_entries = read_u16(counts_offset+0x02,sf);
|
||||||
h->stream_entries = read_u16(counts_offset+0x06,sf);
|
h->stream_entries = read_u16(counts_offset+0x06,sf);
|
||||||
|
|
||||||
|
read_string(h->bank_name, STREAM_NAME_SIZE, bank_name_offset, sf);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -493,7 +541,7 @@ static bool process_headers(STREAMFILE* sf, bnk_header_t* h) {
|
|||||||
|
|
||||||
|
|
||||||
//;VGM_LOG("BNK: subsongs %i, table2_entry=%x, table3_entry=%x\n", h->total_subsongs, h->table2_entry_offset, h->table3_entry_offset);
|
//;VGM_LOG("BNK: subsongs %i, table2_entry=%x, table3_entry=%x\n", h->total_subsongs, h->table2_entry_offset, h->table3_entry_offset);
|
||||||
if (h->target_subsong < 0 || h->target_subsong > h->total_subsongs || h->total_subsongs < 1)
|
if (!h->zlsd_offset && (h->target_subsong < 0 || h->target_subsong > h->total_subsongs || h->total_subsongs < 1))
|
||||||
goto fail;
|
goto fail;
|
||||||
/* this means some subsongs repeat streams, that can happen in some sfx banks, whatevs */
|
/* this means some subsongs repeat streams, that can happen in some sfx banks, whatevs */
|
||||||
if (h->total_subsongs != h->stream_entries) {
|
if (h->total_subsongs != h->stream_entries) {
|
||||||
@ -503,6 +551,10 @@ static bool process_headers(STREAMFILE* sf, bnk_header_t* h) {
|
|||||||
|
|
||||||
//;VGM_LOG("BNK: header entry at %x\n", h->table3_offset + h->table3_entry_offset);
|
//;VGM_LOG("BNK: header entry at %x\n", h->table3_offset + h->table3_entry_offset);
|
||||||
|
|
||||||
|
/* is currently working on ZLSD streams */
|
||||||
|
if (h->zlsd_offset && h->target_subsong > h->total_subsongs)
|
||||||
|
return true;
|
||||||
|
|
||||||
sndh_offset = h->table3_offset + h->table3_entry_offset;
|
sndh_offset = h->table3_offset + h->table3_entry_offset;
|
||||||
|
|
||||||
/* parse sounds */
|
/* parse sounds */
|
||||||
@ -607,10 +659,15 @@ static bool process_names(STREAMFILE* sf, bnk_header_t* h) {
|
|||||||
if (h->table4_offset <= h->sblk_offset)
|
if (h->table4_offset <= h->sblk_offset)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
/* is currently working on ZLSD streams */
|
||||||
|
if (h->zlsd_offset && h->target_subsong > h->total_subsongs)
|
||||||
|
return true;
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
int table4_entry_id = -1;
|
int table4_entry_id = -1;
|
||||||
uint32_t table4_entry_idx, table4_entries_offset, table4_names_offset;
|
uint32_t table4_entry_idx, table4_entries_offset, table4_names_offset;
|
||||||
uint32_t entry_offset, entry_count;
|
uint32_t entry_offset, entry_count;
|
||||||
|
uint32_t stream_name_offset;
|
||||||
|
|
||||||
switch (h->sblk_version) {
|
switch (h->sblk_version) {
|
||||||
case 0x03:
|
case 0x03:
|
||||||
@ -637,29 +694,29 @@ static bool process_names(STREAMFILE* sf, bnk_header_t* h) {
|
|||||||
* and using that as the index for the chunk offsets
|
* and using that as the index for the chunk offsets
|
||||||
* name_sect_offset + (chunk_idx[result] * 0x14);
|
* name_sect_offset + (chunk_idx[result] * 0x14);
|
||||||
*/
|
*/
|
||||||
if (read_u8(h->table4_offset, sf))
|
read_string(h->bank_name, STREAM_NAME_SIZE, h->table4_offset, sf);
|
||||||
h->bank_name_offset = h->table4_offset;
|
|
||||||
|
|
||||||
table4_entries_offset = h->table4_offset + 0x18;
|
table4_entries_offset = h->table4_offset + 0x18;
|
||||||
table4_names_offset = h->table4_offset + read_u32(h->table4_offset + 0x08, sf);
|
table4_names_offset = h->table4_offset + read_u32(h->table4_offset + 0x08, sf);
|
||||||
|
|
||||||
for (i = 0; i < 32; i++) {
|
for (i = 0; i < 32; i++) {
|
||||||
table4_entry_idx = read_u16(table4_entries_offset + (i * 2), sf);
|
table4_entry_idx = read_u16(table4_entries_offset + (i * 2), sf);
|
||||||
h->stream_name_offset = table4_names_offset + (table4_entry_idx * 0x14);
|
stream_name_offset = table4_names_offset + (table4_entry_idx * 0x14);
|
||||||
/* searches the chunk until it finds the target name/index, or breaks at empty name */
|
/* searches the chunk until it finds the target name/index, or breaks at empty name */
|
||||||
while (read_u8(h->stream_name_offset, sf)) {
|
while (read_u8(stream_name_offset, sf)) {
|
||||||
/* in case it goes somewhere out of bounds unexpectedly */
|
/* in case it goes somewhere out of bounds unexpectedly */
|
||||||
if (((read_u8(h->stream_name_offset + 0x00, sf) + read_u8(h->stream_name_offset + 0x04, sf) +
|
if (((read_u8(stream_name_offset + 0x00, sf) + read_u8(stream_name_offset + 0x04, sf) +
|
||||||
read_u8(h->stream_name_offset + 0x08, sf) + read_u8(h->stream_name_offset + 0x0C, sf)) & 0x1F) != i)
|
read_u8(stream_name_offset + 0x08, sf) + read_u8(stream_name_offset + 0x0C, sf)) & 0x1F) != i)
|
||||||
goto fail;
|
goto fail;
|
||||||
if (read_u16(h->stream_name_offset + 0x10, sf) == table4_entry_id)
|
if (read_u16(stream_name_offset + 0x10, sf) == table4_entry_id) {
|
||||||
|
read_string(h->stream_name, STREAM_NAME_SIZE, stream_name_offset, sf);
|
||||||
goto loop_break; /* to break out of the for+while loop simultaneously */
|
goto loop_break; /* to break out of the for+while loop simultaneously */
|
||||||
//break;
|
//break;
|
||||||
h->stream_name_offset += 0x14;
|
}
|
||||||
|
stream_name_offset += 0x14;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//goto fail; /* didn't find any valid index? */
|
//goto fail; /* didn't find any valid index? */
|
||||||
h->stream_name_offset = 0;
|
|
||||||
loop_break:
|
loop_break:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -687,15 +744,15 @@ static bool process_names(STREAMFILE* sf, bnk_header_t* h) {
|
|||||||
* 0x08: ? (2x int16)
|
* 0x08: ? (2x int16)
|
||||||
* 0x0C: section index (int16)
|
* 0x0C: section index (int16)
|
||||||
*/
|
*/
|
||||||
if (read_u8(h->table4_offset, sf))
|
read_string(h->bank_name, STREAM_NAME_SIZE, h->table4_offset, sf);
|
||||||
h->bank_name_offset = h->table4_offset;
|
|
||||||
|
|
||||||
table4_entries_offset = h->table4_offset + read_u32(h->table4_offset + 0x08, sf);
|
table4_entries_offset = h->table4_offset + read_u32(h->table4_offset + 0x08, sf);
|
||||||
table4_names_offset = h->table4_offset + read_u32(h->table4_offset + 0x0C, sf);
|
table4_names_offset = h->table4_offset + read_u32(h->table4_offset + 0x0C, sf);
|
||||||
|
|
||||||
for (i = 0; i < h->sounds_entries; i++) {
|
for (i = 0; i < h->sounds_entries; i++) {
|
||||||
if (read_u16(table4_entries_offset + (i * 0x10) + 0x0C, sf) == table4_entry_id) {
|
if (read_u16(table4_entries_offset + (i * 0x10) + 0x0C, sf) == table4_entry_id) {
|
||||||
h->stream_name_offset = table4_names_offset + read_u32(table4_entries_offset + (i * 0x10), sf);
|
stream_name_offset = table4_names_offset + read_u32(table4_entries_offset + (i * 0x10), sf);
|
||||||
|
read_string(h->stream_name, STREAM_NAME_SIZE, stream_name_offset, sf);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -726,8 +783,7 @@ static bool process_names(STREAMFILE* sf, bnk_header_t* h) {
|
|||||||
/* 0x0c: table4 size */
|
/* 0x0c: table4 size */
|
||||||
/* variable: entries */
|
/* variable: entries */
|
||||||
/* variable: names (null terminated) */
|
/* variable: names (null terminated) */
|
||||||
if (read_u8(h->table4_offset, sf))
|
read_string(h->bank_name, STREAM_NAME_SIZE, h->table4_offset, sf);
|
||||||
h->bank_name_offset = h->table4_offset;
|
|
||||||
|
|
||||||
table4_entries_offset = h->table4_offset + read_u32(h->table4_offset + 0x08, sf);
|
table4_entries_offset = h->table4_offset + read_u32(h->table4_offset + 0x08, sf);
|
||||||
table4_names_offset = table4_entries_offset + (0x10 * h->sounds_entries);
|
table4_names_offset = table4_entries_offset + (0x10 * h->sounds_entries);
|
||||||
@ -737,7 +793,8 @@ static bool process_names(STREAMFILE* sf, bnk_header_t* h) {
|
|||||||
for (i = 0; i < h->sounds_entries; i++) {
|
for (i = 0; i < h->sounds_entries; i++) {
|
||||||
int entry_id = read_u16(table4_entries_offset + (i * 0x10) + 0x0c, sf);
|
int entry_id = read_u16(table4_entries_offset + (i * 0x10) + 0x0c, sf);
|
||||||
if (entry_id == table4_entry_id) {
|
if (entry_id == table4_entry_id) {
|
||||||
h->stream_name_offset = table4_names_offset + read_u32(table4_entries_offset + (i * 0x10) + 0x00, sf);
|
stream_name_offset = table4_names_offset + read_u32(table4_entries_offset + (i * 0x10) + 0x00, sf);
|
||||||
|
read_string(h->stream_name, STREAM_NAME_SIZE, stream_name_offset, sf);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -761,8 +818,13 @@ static bool process_data(STREAMFILE* sf, bnk_header_t* h) {
|
|||||||
read_s32_t read_s32 = h->big_endian ? read_s32be : read_s32le;
|
read_s32_t read_s32 = h->big_endian ? read_s32be : read_s32le;
|
||||||
read_u64_t read_u64 = h->big_endian ? read_u64be : read_u64le;
|
read_u64_t read_u64 = h->big_endian ? read_u64be : read_u64le;
|
||||||
|
|
||||||
|
/* is currently working on ZLSD streams */
|
||||||
|
if (h->zlsd_offset && h->target_subsong > h->total_subsongs)
|
||||||
|
return true;
|
||||||
|
|
||||||
int subtype, loop_length;
|
int subtype, loop_length;
|
||||||
uint32_t extradata_size = 0, postdata_size = 0;
|
uint32_t extradata_size = 0, postdata_size = 0;
|
||||||
|
uint32_t stream_name_size, stream_name_offset;
|
||||||
|
|
||||||
h->start_offset = h->data_offset + h->stream_offset;
|
h->start_offset = h->data_offset + h->stream_offset;
|
||||||
uint32_t info_offset = h->start_offset;
|
uint32_t info_offset = h->start_offset;
|
||||||
@ -907,7 +969,7 @@ static bool process_data(STREAMFILE* sf, bnk_header_t* h) {
|
|||||||
case 0x0c:
|
case 0x0c:
|
||||||
/* has two different variants under the same version - one for PS3 and another for PS4 */
|
/* has two different variants under the same version - one for PS3 and another for PS4 */
|
||||||
|
|
||||||
subtype = read_u32(h->start_offset + 0x00,sf); /* might be u16 at 0x02 instead? (implied by PS4's subtypes) */
|
subtype = read_u16(h->start_offset + 0x02, sf);
|
||||||
if (read_u32(h->start_offset + 0x04, sf) != 0x01) { /* type? */
|
if (read_u32(h->start_offset + 0x04, sf) != 0x01) { /* type? */
|
||||||
VGM_LOG("BNK: unknown subtype\n");
|
VGM_LOG("BNK: unknown subtype\n");
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -958,9 +1020,7 @@ static bool process_data(STREAMFILE* sf, bnk_header_t* h) {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
switch (subtype) { /* PS4 */
|
switch (subtype) { /* PS4 */
|
||||||
/* if subtype is u16 @ 0x02, then 0x00 is PCM and 0x01 is VAG */
|
case 0x00: /* PCM */
|
||||||
case 0x00: /* PCM mono? */
|
|
||||||
case 0x01: /* PCM stereo? */
|
|
||||||
/* 0x10: null? */
|
/* 0x10: null? */
|
||||||
h->channels = read_u32(h->start_offset + 0x14, sf);
|
h->channels = read_u32(h->start_offset + 0x14, sf);
|
||||||
h->interleave = 0x02;
|
h->interleave = 0x02;
|
||||||
@ -972,7 +1032,7 @@ static bool process_data(STREAMFILE* sf, bnk_header_t* h) {
|
|||||||
h->codec = PCM16;
|
h->codec = PCM16;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x10000: /* PS-ADPCM (HEVAG?) */
|
case 0x01: /* PS-ADPCM (HEVAG?) */
|
||||||
/* 0x10: num samples */
|
/* 0x10: num samples */
|
||||||
h->channels = read_u32(h->start_offset + 0x14, sf);
|
h->channels = read_u32(h->start_offset + 0x14, sf);
|
||||||
h->interleave = 0x10;
|
h->interleave = 0x10;
|
||||||
@ -1065,18 +1125,42 @@ static bool process_data(STREAMFILE* sf, bnk_header_t* h) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* pre-info */
|
/* pre-info */
|
||||||
h->stream_name_size = read_u64(info_offset+0x00,sf);
|
stream_name_size = read_u64(info_offset+0x00,sf);
|
||||||
h->stream_name_offset = info_offset + 0x08;
|
stream_name_offset = info_offset + 0x08;
|
||||||
info_offset += h->stream_name_size + 0x08;
|
info_offset += stream_name_size + 0x08;
|
||||||
|
|
||||||
h->stream_size = read_u64(info_offset + 0x00,sf); /* after this offset */
|
h->stream_size = read_u64(info_offset + 0x00,sf); /* after this offset */
|
||||||
h->stream_size += 0x08 + h->stream_name_size + 0x08;
|
h->stream_size += 0x08 + stream_name_size + 0x08;
|
||||||
/* 0x08: max block/etc size? (0x00010000/00030000) */
|
/* 0x08: 0/1 for PCM (Mono/Stereo?), 0/1/2/3 for ATRAC9 (channels/2)? */
|
||||||
/* 0x0c: always 1? */
|
subtype = read_u16(info_offset + 0x0a, sf);
|
||||||
extradata_size = read_u64(info_offset + 0x10,sf) + 0x08 + h->stream_name_size + 0x18;
|
/* 0x0c: always 1 - using this to detect whether it's an SBlk or ZLSD/exteral sound for now */
|
||||||
|
extradata_size = read_u64(info_offset + 0x10,sf) + 0x08 + stream_name_size + 0x18;
|
||||||
|
|
||||||
|
if (stream_name_size >= STREAM_NAME_SIZE || stream_name_size <= 0)
|
||||||
|
stream_name_size = STREAM_NAME_SIZE;
|
||||||
|
read_string(h->stream_name, stream_name_size, stream_name_offset, sf);
|
||||||
|
|
||||||
|
if (read_u32(info_offset + 0x0c, sf) != 0x01) {
|
||||||
|
h->channels = 1;
|
||||||
|
h->codec = EXTERNAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
info_offset += 0x18;
|
info_offset += 0x18;
|
||||||
|
|
||||||
/* actual stream info */
|
/* actual stream info */
|
||||||
|
switch (subtype) {
|
||||||
|
case 0x00: /* PCM */
|
||||||
|
h->num_samples = read_s32(info_offset + 0x00, sf);
|
||||||
|
h->channels = read_u32(info_offset + 0x04, sf);
|
||||||
|
/* 0x08: loop flag? (always -1) */
|
||||||
|
|
||||||
|
h->codec = PCM16;
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* should be split, but 0x1A has no other known codecs yet */
|
||||||
|
case 0x01: /* ATRAC9 (0x23) */
|
||||||
|
case 0x03: /* ATRAC9 (0x1A) */
|
||||||
/* 0x00: extradata size (without pre-info, also above) */
|
/* 0x00: extradata size (without pre-info, also above) */
|
||||||
h->atrac9_info = read_u32be(info_offset + 0x04, sf);
|
h->atrac9_info = read_u32be(info_offset + 0x04, sf);
|
||||||
h->num_samples = read_s32(info_offset + 0x08, sf);
|
h->num_samples = read_s32(info_offset + 0x08, sf);
|
||||||
@ -1085,10 +1169,17 @@ static bool process_data(STREAMFILE* sf, bnk_header_t* h) {
|
|||||||
h->loop_end = read_s32(info_offset + 0x14, sf);
|
h->loop_end = read_s32(info_offset + 0x14, sf);
|
||||||
/* 0x18: loop flag (0=loop, -1=no) */
|
/* 0x18: loop flag (0=loop, -1=no) */
|
||||||
/* rest: null */
|
/* rest: null */
|
||||||
|
|
||||||
|
h->codec = RIFF_ATRAC9;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
vgm_logi("BNK: unknown subtype %x (report)\n", subtype);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
/* no sample rate (probably fixed to 48000/system's, but seen in RIFF) */
|
/* no sample rate (probably fixed to 48000/system's, but seen in RIFF) */
|
||||||
h->sample_rate = 48000;
|
h->sample_rate = 48000;
|
||||||
|
|
||||||
h->codec = RIFF_ATRAC9; /* unsure how other codecs would work */
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -1106,36 +1197,75 @@ fail:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* zlsd part: parse external stream prefetch data */
|
||||||
/* zlsd part: parse extra footer (vox?) data */
|
|
||||||
static bool process_zlsd(STREAMFILE* sf, bnk_header_t* h) {
|
static bool process_zlsd(STREAMFILE* sf, bnk_header_t* h) {
|
||||||
if (!h->zlsd_offset)
|
if (!h->zlsd_offset)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
/* TODO: ZLSD contains FNV1-32 hashes of the SBlk external streams,
|
||||||
|
* but with the way it's all currently set up, it isn't as simple to
|
||||||
|
* map appropriate hashes to existing SBlk streams. So for now these
|
||||||
|
* won't have a "proper" stream name visible.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int zlsd_subsongs, target_subsong;
|
||||||
|
uint32_t zlsd_table_offset, zlsd_table_entry_offset, stream_offset, stream_name_hash;
|
||||||
read_u32_t read_u32 = h->big_endian ? read_u32be : read_u32le;
|
read_u32_t read_u32 = h->big_endian ? read_u32be : read_u32le;
|
||||||
|
|
||||||
if (read_u32(h->zlsd_offset + 0x00, sf) != get_id32be("DSLZ"))
|
if (read_u32(h->zlsd_offset + 0x00, sf) != get_id32be("DSLZ"))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* 0x04: version? (1) */
|
/* 0x04: version? (1) */
|
||||||
int zlsd_count = read_u32(h->zlsd_offset+0x08,sf);
|
zlsd_subsongs = read_u32(h->zlsd_offset + 0x08, sf);
|
||||||
/* 0x0c: start */
|
/* 0x0c: start (most of the time) */
|
||||||
|
/* 0x10: start if 64-bit zlsd_subsongs? seen in SBlk 0x1A */
|
||||||
|
zlsd_table_offset = read_u32(h->zlsd_offset + 0x0C, sf);
|
||||||
/* rest: null */
|
/* rest: null */
|
||||||
|
|
||||||
if (zlsd_count) {
|
/* files can have both SBlk+ZLSD streams */
|
||||||
vgm_logi("BNK: unsupported ZLSD subsongs found\n");
|
if (zlsd_subsongs < 1) {
|
||||||
|
if (h->total_subsongs < 1)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* per entry (for v23)
|
if (!zlsd_table_offset)
|
||||||
* 00: crc (not referenced elsewhere)
|
goto fail; /* 64-bit entries count? */
|
||||||
|
|
||||||
|
/* per entry (for SBlk v0x23)
|
||||||
|
* 00: fnv1-32 hash of the stream name
|
||||||
* 04: stream offset (from this offset)
|
* 04: stream offset (from this offset)
|
||||||
* 08: null (part of offset?)
|
* 08: null (part of offset?)
|
||||||
* 0c: stream size
|
* 0c: stream size
|
||||||
* 10: offset/size?
|
* 10: offset/size?
|
||||||
* 14: null */
|
* 14/18: null */
|
||||||
/* known streams are standard XVAG (no subsongs) */
|
/* known streams are standard XVAG (no subsongs) */
|
||||||
|
|
||||||
|
/* target_subsong is negative if it's working on SBlk streams */
|
||||||
|
target_subsong = h->target_subsong - h->total_subsongs - 1;
|
||||||
|
h->total_subsongs += zlsd_subsongs;
|
||||||
|
|
||||||
|
if (h->target_subsong < 0 || h->target_subsong > h->total_subsongs)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if (target_subsong < 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
zlsd_table_entry_offset = h->zlsd_offset + zlsd_table_offset + target_subsong * 0x18;
|
||||||
|
h->start_offset = zlsd_table_entry_offset + 0x04 + read_u32(zlsd_table_entry_offset + 0x04, sf);
|
||||||
|
h->stream_size = read_u32(zlsd_table_entry_offset + 0x0C, sf);
|
||||||
|
stream_name_hash = read_u32(zlsd_table_entry_offset + 0x00, sf);
|
||||||
|
|
||||||
|
/* should be a switch case, but no other formats known yet */
|
||||||
|
if (!is_id32be(h->start_offset, sf, "XVAG")) {
|
||||||
|
vgm_logi("BNK: unsupported ZLSD subfile found (report)\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(h->stream_name, STREAM_NAME_SIZE, "%u [pre]", stream_name_hash);
|
||||||
|
h->channels = 1; /* dummy, real channels will be retrieved from xvag/riff */
|
||||||
|
h->codec = XVAG_ATRAC9;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
fail:
|
fail:
|
||||||
return false;
|
return false;
|
||||||
@ -1149,7 +1279,7 @@ static bool parse_bnk_v3(STREAMFILE* sf, bnk_header_t* h) {
|
|||||||
if (read_u32be(0x00,sf) == 0x03) { /* PS3 */
|
if (read_u32be(0x00,sf) == 0x03) { /* PS3 */
|
||||||
h->big_endian = 1;
|
h->big_endian = 1;
|
||||||
}
|
}
|
||||||
else if (read_u32le(0x00,sf) == 0x03) { /* PS2/PSP/Vita/PS4 */
|
else if (read_u32le(0x00,sf) == 0x03) { /* PS2/PSP/Vita/PS4/PS5 */
|
||||||
h->big_endian = 0;
|
h->big_endian = 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -1163,7 +1293,7 @@ static bool parse_bnk_v3(STREAMFILE* sf, bnk_header_t* h) {
|
|||||||
return false;
|
return false;
|
||||||
/* in theory a bank can contain multiple blocks but only those are used */
|
/* in theory a bank can contain multiple blocks but only those are used */
|
||||||
|
|
||||||
/* section sizes don't include padding (sometimes aligned to 0x10/0x800) */
|
/* file is sometimes aligned to 0x10/0x800, so this can't be used for total size checks */
|
||||||
h->sblk_offset = read_u32(0x08,sf);
|
h->sblk_offset = read_u32(0x08,sf);
|
||||||
//h->sblk_size = read_u32(0x0c,sf);
|
//h->sblk_size = read_u32(0x0c,sf);
|
||||||
h->data_offset = read_u32(0x10,sf);
|
h->data_offset = read_u32(0x10,sf);
|
||||||
@ -1195,12 +1325,12 @@ static bool parse_bnk_v3(STREAMFILE* sf, bnk_header_t* h) {
|
|||||||
* - 0x10: block number
|
* - 0x10: block number
|
||||||
* - 0x11: padding
|
* - 0x11: padding
|
||||||
* version >= v0x1a:
|
* version >= v0x1a:
|
||||||
* - 0x0c: hash (0x10)
|
* - 0x0c: uuid (0x10)
|
||||||
* - 0x1c: filename (0x100?)
|
* - 0x1c: bank name (0x100?)
|
||||||
* version ~= v0x23:
|
* version ~= v0x23:
|
||||||
* - 0x0c: null (depends on flags? v1a=0x05, v23=0x07)
|
* - 0x0c: null (depends on flags? v1a=0x05, v23=0x07)
|
||||||
* - 0x10: hash (0x10)
|
* - 0x10: uuid (0x10)
|
||||||
* - 0x20: filename (0x100?)
|
* - 0x20: bank name (0x100?)
|
||||||
*/
|
*/
|
||||||
//;VGM_LOG("BNK: h->sblk_offset=%lx, h->data_offset=%lx, h->sblk_version %x\n", h->sblk_offset, h->data_offset, h->sblk_version);
|
//;VGM_LOG("BNK: h->sblk_offset=%lx, h->data_offset=%lx, h->sblk_version %x\n", h->sblk_offset, h->data_offset, h->sblk_version);
|
||||||
//TODO handle, in rare cases may contain subsongs (unsure how are referenced but has its own number)
|
//TODO handle, in rare cases may contain subsongs (unsure how are referenced but has its own number)
|
||||||
|
Loading…
Reference in New Issue
Block a user