From 39c3b9583ba6180fe8330dddb767ef07d2ff320a Mon Sep 17 00:00:00 2001 From: EdnessP <55930127+EdnessP@users.noreply.github.com> Date: Fri, 6 Sep 2024 10:43:10 +0300 Subject: [PATCH 1/9] Sony BNK: read bank/stream names asap --- src/meta/bnk_sony.c | 60 ++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 33 deletions(-) diff --git a/src/meta/bnk_sony.c b/src/meta/bnk_sony.c index 7c4c57a0..f758d8ad 100644 --- a/src/meta/bnk_sony.c +++ b/src/meta/bnk_sony.c @@ -47,9 +47,6 @@ typedef struct { uint32_t start_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 interleave; @@ -85,15 +82,6 @@ VGMSTREAM* init_vgmstream_bnk_sony(STREAMFILE* sf) { 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]) { get_streamfile_basename(sf, file_name, STREAM_NAME_SIZE); if (h.bank_name[0] && strcmp(file_name, h.bank_name) != 0) @@ -611,6 +599,7 @@ static bool process_names(STREAMFILE* sf, bnk_header_t* h) { int table4_entry_id = -1; uint32_t table4_entry_idx, table4_entries_offset, table4_names_offset; uint32_t entry_offset, entry_count; + uint32_t stream_name_offset; switch (h->sblk_version) { case 0x03: @@ -637,30 +626,30 @@ static bool process_names(STREAMFILE* sf, bnk_header_t* h) { * and using that as the index for the chunk offsets * name_sect_offset + (chunk_idx[result] * 0x14); */ - if (read_u8(h->table4_offset, sf)) - h->bank_name_offset = h->table4_offset; + read_string(h->bank_name, STREAM_NAME_SIZE, h->table4_offset, sf); table4_entries_offset = h->table4_offset + 0x18; table4_names_offset = h->table4_offset + read_u32(h->table4_offset + 0x08, sf); for (i = 0; i < 32; i++) { 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 */ - while (read_u8(h->stream_name_offset, sf)) { + while (read_u8(stream_name_offset, sf)) { /* 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) + - read_u8(h->stream_name_offset + 0x08, sf) + read_u8(h->stream_name_offset + 0x0C, sf)) & 0x1F) != i) + if (((read_u8(stream_name_offset + 0x00, sf) + read_u8(stream_name_offset + 0x04, sf) + + read_u8(stream_name_offset + 0x08, sf) + read_u8(stream_name_offset + 0x0C, sf)) & 0x1F) != i) 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 */ //break; - h->stream_name_offset += 0x14; + } + stream_name_offset += 0x14; } } //goto fail; /* didn't find any valid index? */ - h->stream_name_offset = 0; - loop_break: +loop_break: break; case 0x04: @@ -687,15 +676,15 @@ static bool process_names(STREAMFILE* sf, bnk_header_t* h) { * 0x08: ? (2x int16) * 0x0C: section index (int16) */ - if (read_u8(h->table4_offset, sf)) - h->bank_name_offset = h->table4_offset; + read_string(h->bank_name, STREAM_NAME_SIZE, h->table4_offset, 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); for (i = 0; i < h->sounds_entries; i++) { 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; } } @@ -726,8 +715,7 @@ static bool process_names(STREAMFILE* sf, bnk_header_t* h) { /* 0x0c: table4 size */ /* variable: entries */ /* variable: names (null terminated) */ - if (read_u8(h->table4_offset, sf)) - h->bank_name_offset = h->table4_offset; + read_string(h->bank_name, STREAM_NAME_SIZE, h->table4_offset, sf); table4_entries_offset = h->table4_offset + read_u32(h->table4_offset + 0x08, sf); table4_names_offset = table4_entries_offset + (0x10 * h->sounds_entries); @@ -737,7 +725,8 @@ static bool process_names(STREAMFILE* sf, bnk_header_t* h) { for (i = 0; i < h->sounds_entries; i++) { int entry_id = read_u16(table4_entries_offset + (i * 0x10) + 0x0c, sf); 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; } } @@ -763,6 +752,7 @@ static bool process_data(STREAMFILE* sf, bnk_header_t* h) { int subtype, loop_length; 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; uint32_t info_offset = h->start_offset; @@ -1065,17 +1055,21 @@ static bool process_data(STREAMFILE* sf, bnk_header_t* h) { } /* pre-info */ - h->stream_name_size = read_u64(info_offset+0x00,sf); - h->stream_name_offset = info_offset + 0x08; - info_offset += h->stream_name_size + 0x08; + stream_name_size = read_u64(info_offset+0x00,sf); + stream_name_offset = info_offset + 0x08; + info_offset += stream_name_size + 0x08; 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) */ /* 0x0c: always 1? */ - extradata_size = read_u64(info_offset + 0x10,sf) + 0x08 + h->stream_name_size + 0x18; + extradata_size = read_u64(info_offset + 0x10,sf) + 0x08 + stream_name_size + 0x18; info_offset += 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); + /* actual stream info */ /* 0x00: extradata size (without pre-info, also above) */ h->atrac9_info = read_u32be(info_offset+0x04,sf); From fcd58d3c1b398c24f5bdcf99cc5eb0c8d3c7713e Mon Sep 17 00:00:00 2001 From: EdnessP <55930127+EdnessP@users.noreply.github.com> Date: Fri, 6 Sep 2024 11:35:59 +0300 Subject: [PATCH 2/9] Sony BNK: 0x1A/0x23 bank names --- src/meta/bnk_sony.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/meta/bnk_sony.c b/src/meta/bnk_sony.c index f758d8ad..9c604532 100644 --- a/src/meta/bnk_sony.c +++ b/src/meta/bnk_sony.c @@ -384,9 +384,10 @@ static bool process_tables(STREAMFILE* sf, bnk_header_t* h) { h->table2_suboffset = 0x00; 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 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 counts_offset = tables_offset + (h->sblk_version <= 0x1a ? 0x98 : 0xb0); @@ -396,6 +397,8 @@ static bool process_tables(STREAMFILE* sf, bnk_header_t* h) { //h->sounds_entries = read_u16(counts_offset+0x00,sf); //h->grains_entries = read_u16(counts_offset+0x02,sf); h->stream_entries = read_u16(counts_offset+0x06,sf); + + read_string(h->bank_name, STREAM_NAME_SIZE, bank_name_offset, sf); break; } From 05566592840bda0244b1a5e7d938a1138acab914 Mon Sep 17 00:00:00 2001 From: EdnessP <55930127+EdnessP@users.noreply.github.com> Date: Sat, 7 Sep 2024 18:12:55 +0300 Subject: [PATCH 3/9] Sony BNK: 0x23 codecs --- src/meta/bnk_sony.c | 88 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 69 insertions(+), 19 deletions(-) diff --git a/src/meta/bnk_sony.c b/src/meta/bnk_sony.c index 9c604532..cccc5f32 100644 --- a/src/meta/bnk_sony.c +++ b/src/meta/bnk_sony.c @@ -459,6 +459,24 @@ static bool process_headers(STREAMFILE* sf, bnk_header_t* h) { case 0x23: h->total_subsongs = h->stream_entries; h->table3_entry_offset = (h->target_subsong - 1) * 0x08; + + /* find the amount of external/ZLSD subsongs in SBlk to skip, see process_data() for more info */ + for (i = 0; i < h->stream_entries; i++) { + uint32_t stream_offset = read_u32(h->table3_offset + h->table3_entry_offset + i * 0x08, sf); + /* some rare files (vox-joel.bnk) have dummy streams sprinkled between external ones, which kinda break it */ + /* maybe at that point also find exclude and skip dummy streams from being loaded? */ + if (stream_offset == 0xFFFFFFFF) { + //if (skip_dummy_streams) h->total_subsongs--; + continue; + } + stream_offset += h->data_offset; + + uint32_t stream_name_size = read_u32(stream_offset + 0x00, sf); + if (read_u32(stream_offset + 0x08 + stream_name_size + 0x0C, sf) != 0x01) + h->total_subsongs--; + } + vgm_logi("h->total_subsongs = %d / h->stream_entries = %d\n", h->total_subsongs, h->stream_entries); + break; default: @@ -1064,28 +1082,58 @@ static bool process_data(STREAMFILE* sf, bnk_header_t* h) { h->stream_size = read_u64(info_offset + 0x00,sf); /* after this offset */ h->stream_size += 0x08 + stream_name_size + 0x08; - /* 0x08: max block/etc size? (0x00010000/00030000) */ - /* 0x0c: always 1? */ + /* 0x08: 0/1 for PCM (Mono/Stereo?), 0/1/2/3 for ATRAC9 (channels/2 except mono=0?) */ + subtype = read_u16(info_offset + 0x0a, sf); + /* 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; - info_offset += 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); + /* is there a better way to detect? name size isn't aligned for these either, so ext check also works */ + /* the name likely has to be hashed and that can be used to find the appropeiate ZLSD entry */ + //if (is_id32be(info_offset - 0x5, sf, "xvag")) break; /* extension */ + if (read_u32(info_offset + 0x0c, sf) != 0x01) { + //h->external_subsongs++; /* total calculated and subtracted in process_headers() */ + /* for external/zlsd this will just read the stream name from the next entry, or 0 for the last one */ + break; + } + + info_offset += 0x18; + /* actual stream info */ - /* 0x00: extradata size (without pre-info, also above) */ - h->atrac9_info = read_u32be(info_offset+0x04,sf); - h->num_samples = read_s32(info_offset+0x08,sf); - h->channels = read_u32(info_offset+0x0c,sf); - h->loop_start = read_s32(info_offset+0x10,sf); - h->loop_end = read_s32(info_offset+0x14,sf); - /* 0x18: loop flag (0=loop, -1=no) */ - /* rest: null */ + switch (subtype) { + case 0x00: + 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: /* 0x23 */ + case 0x03: /* 0x1A */ + /* 0x00: extradata size (without pre-info, also above) */ + h->atrac9_info = read_u32be(info_offset + 0x04, sf); + h->num_samples = read_s32(info_offset + 0x08, sf); + h->channels = read_u32(info_offset + 0x0c, sf); + h->loop_start = read_s32(info_offset + 0x10, sf); + h->loop_end = read_s32(info_offset + 0x14, sf); + /* 0x18: loop flag (0=loop, -1=no) */ + /* 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) */ h->sample_rate = 48000; - - h->codec = RIFF_ATRAC9; /* unsure how other codecs would work */ break; default: @@ -1103,7 +1151,6 @@ fail: return false; } - /* zlsd part: parse extra footer (vox?) data */ static bool process_zlsd(STREAMFILE* sf, bnk_header_t* h) { if (!h->zlsd_offset) @@ -1117,11 +1164,14 @@ static bool process_zlsd(STREAMFILE* sf, bnk_header_t* h) { /* 0x04: version? (1) */ int zlsd_count = read_u32(h->zlsd_offset+0x08,sf); /* 0x0c: start */ + /* 0x10: start if 64-bit zlsd_count? seen in SBlk 0x1A */ /* rest: null */ if (zlsd_count) { vgm_logi("BNK: unsupported ZLSD subsongs found\n"); - goto fail; + /* there are files with both SBlk+ZLSD streams */ + /* returning false means none of those streams will work either */ + return true; } /* per entry (for v23) @@ -1192,12 +1242,12 @@ static bool parse_bnk_v3(STREAMFILE* sf, bnk_header_t* h) { * - 0x10: block number * - 0x11: padding * version >= v0x1a: - * - 0x0c: hash (0x10) - * - 0x1c: filename (0x100?) + * - 0x0c: uuid (0x10) + * - 0x1c: bank name (0x100?) * version ~= v0x23: * - 0x0c: null (depends on flags? v1a=0x05, v23=0x07) - * - 0x10: hash (0x10) - * - 0x20: filename (0x100?) + * - 0x10: uuid (0x10) + * - 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); //TODO handle, in rare cases may contain subsongs (unsure how are referenced but has its own number) From 9ba1c3bfc46fcf64b0f3e00cc835a92ee5213111 Mon Sep 17 00:00:00 2001 From: EdnessP <55930127+EdnessP@users.noreply.github.com> Date: Sat, 7 Sep 2024 21:24:22 +0300 Subject: [PATCH 4/9] Sony BNK: SBlk 0x23 fixes and ZLSD streams --- src/meta/bnk_sony.c | 111 ++++++++++++++++++++++++++++---------------- 1 file changed, 70 insertions(+), 41 deletions(-) diff --git a/src/meta/bnk_sony.c b/src/meta/bnk_sony.c index cccc5f32..2dfd1434 100644 --- a/src/meta/bnk_sony.c +++ b/src/meta/bnk_sony.c @@ -3,7 +3,7 @@ #include "../coding/coding.h" #include "../util/endianness.h" -typedef enum { NONE, DUMMY, PSX, PCM16, MPEG, ATRAC9, HEVAG, RIFF_ATRAC9 } bnk_codec; +typedef enum { NONE, DUMMY, PSX, PCM16, MPEG, ATRAC9, HEVAG, RIFF_ATRAC9, XVAG_ATRAC9 } bnk_codec; typedef struct { bnk_codec codec; @@ -66,10 +66,10 @@ VGMSTREAM* init_vgmstream_bnk_sony(STREAMFILE* sf) { bnk_header_t h = {0}; /* checks */ - if (!parse_bnk_v3(sf, &h)) - return NULL; if (!check_extensions(sf, "bnk")) return NULL; + if (!parse_bnk_v3(sf, &h)) + return NULL; /* build the VGMSTREAM */ @@ -142,6 +142,27 @@ VGMSTREAM* init_vgmstream_bnk_sony(STREAMFILE* sf) { close_vgmstream(vgmstream); 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_vs = init_vgmstream_xvag(temp_sf); + close_streamfile(temp_sf); + if (!temp_vs) goto fail; + + 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 #ifdef VGM_USE_MPEG case MPEG: { @@ -457,25 +478,23 @@ static bool process_headers(STREAMFILE* sf, bnk_header_t* h) { case 0x1a: case 0x23: - h->total_subsongs = h->stream_entries; - h->table3_entry_offset = (h->target_subsong - 1) * 0x08; - - /* find the amount of external/ZLSD subsongs in SBlk to skip, see process_data() for more info */ for (i = 0; i < h->stream_entries; i++) { - uint32_t stream_offset = read_u32(h->table3_offset + h->table3_entry_offset + i * 0x08, sf); - /* some rare files (vox-joel.bnk) have dummy streams sprinkled between external ones, which kinda break it */ - /* maybe at that point also find exclude and skip dummy streams from being loaded? */ - if (stream_offset == 0xFFFFFFFF) { - //if (skip_dummy_streams) h->total_subsongs--; + /* skip dummy/silence streams */ + uint32_t stream_offset = read_u32(h->table3_offset + i * 0x08, sf); + if (stream_offset == 0xFFFFFFFF) continue; - } - stream_offset += h->data_offset; + /* skip ZLSD/external streams */ + stream_offset += h->data_offset; uint32_t stream_name_size = read_u32(stream_offset + 0x00, sf); if (read_u32(stream_offset + 0x08 + stream_name_size + 0x0C, sf) != 0x01) - h->total_subsongs--; + continue; + + h->total_subsongs++; + if (h->total_subsongs == h->target_subsong) + h->table3_entry_offset = i * 0x08; + /* continue to count all subsongs */ } - vgm_logi("h->total_subsongs = %d / h->stream_entries = %d\n", h->total_subsongs, h->stream_entries); break; @@ -502,7 +521,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); - 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; /* this means some subsongs repeat streams, that can happen in some sfx banks, whatevs */ if (h->total_subsongs != h->stream_entries) { @@ -1069,12 +1088,6 @@ static bool process_data(STREAMFILE* sf, bnk_header_t* h) { case 0x1a: case 0x23: - if (h->stream_offset == 0xFFFFFFFF) { - h->channels = 1; - h->codec = DUMMY; - break; - } - /* pre-info */ stream_name_size = read_u64(info_offset+0x00,sf); stream_name_offset = info_offset + 0x08; @@ -1091,20 +1104,15 @@ static bool process_data(STREAMFILE* sf, bnk_header_t* h) { stream_name_size = STREAM_NAME_SIZE; read_string(h->stream_name, stream_name_size, stream_name_offset, sf); - /* is there a better way to detect? name size isn't aligned for these either, so ext check also works */ - /* the name likely has to be hashed and that can be used to find the appropeiate ZLSD entry */ - //if (is_id32be(info_offset - 0x5, sf, "xvag")) break; /* extension */ - if (read_u32(info_offset + 0x0c, sf) != 0x01) { - //h->external_subsongs++; /* total calculated and subtracted in process_headers() */ - /* for external/zlsd this will just read the stream name from the next entry, or 0 for the last one */ + /* the stream name likely has to be hashed and that can be used to find the appropeiate ZLSD entry */ + if (read_u32(info_offset + 0x0c, sf) != 0x01) break; - } info_offset += 0x18; /* actual stream info */ switch (subtype) { - case 0x00: + 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) */ @@ -1113,8 +1121,8 @@ static bool process_data(STREAMFILE* sf, bnk_header_t* h) { break; /* should be split, but 0x1A has no other known codecs yet */ - case 0x01: /* 0x23 */ - case 0x03: /* 0x1A */ + case 0x01: /* ATRAC9 (0x23) */ + case 0x03: /* ATRAC9 (0x1A) */ /* 0x00: extradata size (without pre-info, also above) */ h->atrac9_info = read_u32be(info_offset + 0x04, sf); h->num_samples = read_s32(info_offset + 0x08, sf); @@ -1156,21 +1164,24 @@ static bool process_zlsd(STREAMFILE* sf, bnk_header_t* h) { if (!h->zlsd_offset) return true; + int zlsd_entries, target_subsong; + uint32_t zlsd_table_offset, zlsd_table_entry_offset, stream_offset; 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; /* 0x04: version? (1) */ - int zlsd_count = read_u32(h->zlsd_offset+0x08,sf); - /* 0x0c: start */ - /* 0x10: start if 64-bit zlsd_count? seen in SBlk 0x1A */ + zlsd_entries = read_u32(h->zlsd_offset + 0x08, sf); + /* 0x0c: start (most of the time) */ + /* 0x10: start if 64-bit zlsd_entries? seen in SBlk 0x1A */ + zlsd_table_offset = read_u32(h->zlsd_offset + 0x0C, sf); /* rest: null */ - if (zlsd_count) { - vgm_logi("BNK: unsupported ZLSD subsongs found\n"); - /* there are files with both SBlk+ZLSD streams */ - /* returning false means none of those streams will work either */ + /* files can have both SBlk+ZLSD streams */ + if (!zlsd_entries) { + if (!h->total_subsongs) + goto fail; return true; } @@ -1183,6 +1194,24 @@ static bool process_zlsd(STREAMFILE* sf, bnk_header_t* h) { * 14: null */ /* known streams are standard XVAG (no subsongs) */ + /* negative if still working on SBlk streams */ + target_subsong = h->target_subsong - h->total_subsongs - 1; + + if (target_subsong >= 0) { + 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); + + /* should be a switch case, but no other formats known yet */ + //if (!is_id32be(h->stream_offset, sf, "XVAG")) goto fail; + + h->codec = XVAG_ATRAC9; + h->channels = 1; /* dummy, real channels will be retrieved from xvag/riff */ + } + + h->total_subsongs += zlsd_entries; + return true; fail: return false; From 627196bba52d6461a4c3166dac2d88be76876b0c Mon Sep 17 00:00:00 2001 From: EdnessP <55930127+EdnessP@users.noreply.github.com> Date: Sat, 7 Sep 2024 22:15:07 +0300 Subject: [PATCH 5/9] Sony BNK: cleanup --- src/meta/bnk_sony.c | 45 ++++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/src/meta/bnk_sony.c b/src/meta/bnk_sony.c index 2dfd1434..406858b5 100644 --- a/src/meta/bnk_sony.c +++ b/src/meta/bnk_sony.c @@ -150,6 +150,7 @@ VGMSTREAM* init_vgmstream_bnk_sony(STREAMFILE* sf) { 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); @@ -937,7 +938,7 @@ static bool process_data(STREAMFILE* sf, bnk_header_t* h) { case 0x0c: /* 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? */ VGM_LOG("BNK: unknown subtype\n"); goto fail; @@ -988,9 +989,7 @@ static bool process_data(STREAMFILE* sf, bnk_header_t* h) { } else { switch (subtype) { /* PS4 */ - /* if subtype is u16 @ 0x02, then 0x00 is PCM and 0x01 is VAG */ - case 0x00: /* PCM mono? */ - case 0x01: /* PCM stereo? */ + case 0x00: /* PCM */ /* 0x10: null? */ h->channels = read_u32(h->start_offset + 0x14, sf); h->interleave = 0x02; @@ -1002,7 +1001,7 @@ static bool process_data(STREAMFILE* sf, bnk_header_t* h) { h->codec = PCM16; break; - case 0x10000: /* PS-ADPCM (HEVAG?) */ + case 0x01: /* PS-ADPCM (HEVAG?) */ /* 0x10: num samples */ h->channels = read_u32(h->start_offset + 0x14, sf); h->interleave = 0x10; @@ -1179,11 +1178,8 @@ static bool process_zlsd(STREAMFILE* sf, bnk_header_t* h) { /* rest: null */ /* files can have both SBlk+ZLSD streams */ - if (!zlsd_entries) { - if (!h->total_subsongs) - goto fail; + if (!zlsd_entries) return true; - } /* per entry (for v23) * 00: crc (not referenced elsewhere) @@ -1196,22 +1192,25 @@ static bool process_zlsd(STREAMFILE* sf, bnk_header_t* h) { /* negative if still working on SBlk streams */ target_subsong = h->target_subsong - h->total_subsongs - 1; - - if (target_subsong >= 0) { - 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); - - /* should be a switch case, but no other formats known yet */ - //if (!is_id32be(h->stream_offset, sf, "XVAG")) goto fail; - - h->codec = XVAG_ATRAC9; - h->channels = 1; /* dummy, real channels will be retrieved from xvag/riff */ - } - h->total_subsongs += zlsd_entries; + if (h->target_subsong < 0 || h->target_subsong > h->total_subsongs || h->total_subsongs < 1) + 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); + + /* should be a switch case, but no other formats known yet */ + if (!is_id32be(h->start_offset, sf, "XVAG")) goto fail; + + h->codec = XVAG_ATRAC9; + h->channels = 1; /* dummy, real channels will be retrieved from xvag/riff */ + return true; fail: return false; From 9413f6f8dcfdab33cdf46b410772f960c2c5f09a Mon Sep 17 00:00:00 2001 From: EdnessP <55930127+EdnessP@users.noreply.github.com> Date: Sat, 7 Sep 2024 22:44:20 +0300 Subject: [PATCH 6/9] Sony BNK: cleanup --- src/meta/bnk_sony.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/meta/bnk_sony.c b/src/meta/bnk_sony.c index 406858b5..febfe7f4 100644 --- a/src/meta/bnk_sony.c +++ b/src/meta/bnk_sony.c @@ -1094,7 +1094,7 @@ static bool process_data(STREAMFILE* sf, bnk_header_t* h) { h->stream_size = read_u64(info_offset + 0x00,sf); /* after this offset */ h->stream_size += 0x08 + stream_name_size + 0x08; - /* 0x08: 0/1 for PCM (Mono/Stereo?), 0/1/2/3 for ATRAC9 (channels/2 except mono=0?) */ + /* 0x08: 0/1 for PCM (Mono/Stereo?), 0/1/2/3 for ATRAC9 (channels/2)? */ subtype = read_u16(info_offset + 0x0a, sf); /* 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; @@ -1206,7 +1206,11 @@ static bool process_zlsd(STREAMFILE* sf, bnk_header_t* h) { h->stream_size = read_u32(zlsd_table_entry_offset + 0x0C, sf); /* should be a switch case, but no other formats known yet */ - if (!is_id32be(h->start_offset, sf, "XVAG")) goto fail; + if (!is_id32be(h->start_offset, sf, "XVAG")) { + /* maybe also a separate warning if XVAG returns more than 1 subsong? */ + vgm_logi("BNK: unsupported ZLSD subtype found (report)\n"); + goto fail; + } h->codec = XVAG_ATRAC9; h->channels = 1; /* dummy, real channels will be retrieved from xvag/riff */ From 17afd7830471c358bb0b562bfa76affe1d7eadbd Mon Sep 17 00:00:00 2001 From: EdnessP <55930127+EdnessP@users.noreply.github.com> Date: Sun, 8 Sep 2024 10:36:00 +0300 Subject: [PATCH 7/9] Sony BNK: cleanup/skip processing SBlk for ZLSD streams --- src/meta/bnk_sony.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/meta/bnk_sony.c b/src/meta/bnk_sony.c index febfe7f4..29653e9a 100644 --- a/src/meta/bnk_sony.c +++ b/src/meta/bnk_sony.c @@ -159,7 +159,7 @@ VGMSTREAM* init_vgmstream_bnk_sony(STREAMFILE* sf) { 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); + strcpy(temp_vs->stream_name, vgmstream->stream_name); close_vgmstream(vgmstream); return temp_vs; @@ -532,6 +532,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); + /* 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; /* parse sounds */ @@ -636,6 +640,10 @@ static bool process_names(STREAMFILE* sf, bnk_header_t* h) { if (h->table4_offset <= h->sblk_offset) return true; + /* is currently working on ZLSD streams */ + if (h->zlsd_offset && h->target_subsong > h->total_subsongs) + return true; + int i; int table4_entry_id = -1; uint32_t table4_entry_idx, table4_entries_offset, table4_names_offset; @@ -791,6 +799,10 @@ static bool process_data(STREAMFILE* sf, bnk_header_t* h) { read_s32_t read_s32 = h->big_endian ? read_s32be : read_s32le; 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; uint32_t extradata_size = 0, postdata_size = 0; uint32_t stream_name_size, stream_name_offset; @@ -1104,8 +1116,7 @@ static bool process_data(STREAMFILE* sf, bnk_header_t* h) { read_string(h->stream_name, stream_name_size, stream_name_offset, sf); /* the stream name likely has to be hashed and that can be used to find the appropeiate ZLSD entry */ - if (read_u32(info_offset + 0x0c, sf) != 0x01) - break; + //if (read_u32(info_offset + 0x0c, sf) != 0x01) break; info_offset += 0x18; @@ -1190,7 +1201,7 @@ static bool process_zlsd(STREAMFILE* sf, bnk_header_t* h) { * 14: null */ /* known streams are standard XVAG (no subsongs) */ - /* negative if still working on SBlk streams */ + /* target_subsong is negative if it's working on SBlk streams */ target_subsong = h->target_subsong - h->total_subsongs - 1; h->total_subsongs += zlsd_entries; @@ -1201,14 +1212,13 @@ static bool process_zlsd(STREAMFILE* sf, bnk_header_t* h) { 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); /* should be a switch case, but no other formats known yet */ if (!is_id32be(h->start_offset, sf, "XVAG")) { /* maybe also a separate warning if XVAG returns more than 1 subsong? */ - vgm_logi("BNK: unsupported ZLSD subtype found (report)\n"); + vgm_logi("BNK: unsupported ZLSD subfile found (report)\n"); goto fail; } @@ -1224,11 +1234,11 @@ fail: /* parse SCREAM bnk (usually SFX but also used for music) */ static bool parse_bnk_v3(STREAMFILE* sf, bnk_header_t* h) { - /* bnk/SCREAM tool version (v2 is a bit different, not seen v1) */ + /* bnk/SCREAM tool version (v2 is a bit different, not seen v1) */ if (read_u32be(0x00,sf) == 0x03) { /* PS3 */ 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; } else { @@ -1242,7 +1252,7 @@ static bool parse_bnk_v3(STREAMFILE* sf, bnk_header_t* h) { return false; /* 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_size = read_u32(0x0c,sf); h->data_offset = read_u32(0x10,sf); From c622a16653101f2004181853418d65fd613ffdaf Mon Sep 17 00:00:00 2001 From: EdnessP <55930127+EdnessP@users.noreply.github.com> Date: Sun, 8 Sep 2024 12:30:34 +0300 Subject: [PATCH 8/9] Sony BNK: fix ZLSD safety checks --- src/meta/bnk_sony.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/meta/bnk_sony.c b/src/meta/bnk_sony.c index 29653e9a..1b3ef356 100644 --- a/src/meta/bnk_sony.c +++ b/src/meta/bnk_sony.c @@ -1174,7 +1174,7 @@ static bool process_zlsd(STREAMFILE* sf, bnk_header_t* h) { if (!h->zlsd_offset) return true; - int zlsd_entries, target_subsong; + int zlsd_subsongs, target_subsong; uint32_t zlsd_table_offset, zlsd_table_entry_offset, stream_offset; read_u32_t read_u32 = h->big_endian ? read_u32be : read_u32le; @@ -1182,17 +1182,23 @@ static bool process_zlsd(STREAMFILE* sf, bnk_header_t* h) { return false; /* 0x04: version? (1) */ - zlsd_entries = read_u32(h->zlsd_offset + 0x08, sf); + zlsd_subsongs = read_u32(h->zlsd_offset + 0x08, sf); /* 0x0c: start (most of the time) */ - /* 0x10: start if 64-bit zlsd_entries? seen in SBlk 0x1A */ + /* 0x10: start if 64-bit zlsd_subsongs? seen in SBlk 0x1A */ zlsd_table_offset = read_u32(h->zlsd_offset + 0x0C, sf); /* rest: null */ /* files can have both SBlk+ZLSD streams */ - if (!zlsd_entries) + if (zlsd_subsongs < 1) { + if (h->total_subsongs < 1) + goto fail; return true; + } - /* per entry (for v23) + if (!zlsd_table_offset) + goto fail; /* 64-bit entries count? */ + + /* per entry (for SBlk v0x23) * 00: crc (not referenced elsewhere) * 04: stream offset (from this offset) * 08: null (part of offset?) @@ -1203,9 +1209,9 @@ static bool process_zlsd(STREAMFILE* sf, bnk_header_t* h) { /* target_subsong is negative if it's working on SBlk streams */ target_subsong = h->target_subsong - h->total_subsongs - 1; - h->total_subsongs += zlsd_entries; + h->total_subsongs += zlsd_subsongs; - if (h->target_subsong < 0 || h->target_subsong > h->total_subsongs || h->total_subsongs < 1) + if (h->target_subsong < 0 || h->target_subsong > h->total_subsongs) goto fail; if (target_subsong < 0) From 7bf2ea11d075b8550f2d38c1767fcdcb3e9fbb66 Mon Sep 17 00:00:00 2001 From: EdnessP <55930127+EdnessP@users.noreply.github.com> Date: Mon, 9 Sep 2024 11:39:16 +0300 Subject: [PATCH 9/9] Sony BNK: rework ZLSD/external lookup --- src/meta/bnk_sony.c | 89 +++++++++++++++++++++++++++++++-------------- 1 file changed, 62 insertions(+), 27 deletions(-) diff --git a/src/meta/bnk_sony.c b/src/meta/bnk_sony.c index 1b3ef356..dc4e16f7 100644 --- a/src/meta/bnk_sony.c +++ b/src/meta/bnk_sony.c @@ -3,7 +3,7 @@ #include "../coding/coding.h" #include "../util/endianness.h" -typedef enum { NONE, DUMMY, PSX, PCM16, MPEG, ATRAC9, HEVAG, RIFF_ATRAC9, XVAG_ATRAC9 } bnk_codec; +typedef enum { NONE, DUMMY, EXTERNAL, PSX, PCM16, MPEG, ATRAC9, HEVAG, RIFF_ATRAC9, XVAG_ATRAC9 } bnk_codec; typedef struct { bnk_codec codec; @@ -103,6 +103,39 @@ VGMSTREAM* init_vgmstream_bnk_sony(STREAMFILE* sf) { 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 case ATRAC9: { atrac9_config cfg = {0}; @@ -156,6 +189,8 @@ VGMSTREAM* init_vgmstream_bnk_sony(STREAMFILE* 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; @@ -479,24 +514,8 @@ static bool process_headers(STREAMFILE* sf, bnk_header_t* h) { case 0x1a: case 0x23: - for (i = 0; i < h->stream_entries; i++) { - /* skip dummy/silence streams */ - uint32_t stream_offset = read_u32(h->table3_offset + i * 0x08, sf); - if (stream_offset == 0xFFFFFFFF) - continue; - - /* skip ZLSD/external streams */ - stream_offset += h->data_offset; - uint32_t stream_name_size = read_u32(stream_offset + 0x00, sf); - if (read_u32(stream_offset + 0x08 + stream_name_size + 0x0C, sf) != 0x01) - continue; - - h->total_subsongs++; - if (h->total_subsongs == h->target_subsong) - h->table3_entry_offset = i * 0x08; - /* continue to count all subsongs */ - } - + h->total_subsongs = h->stream_entries; + h->table3_entry_offset = (h->target_subsong - 1) * 0x08; break; default: @@ -1099,6 +1118,12 @@ static bool process_data(STREAMFILE* sf, bnk_header_t* h) { case 0x1a: case 0x23: + if (h->stream_offset == 0xFFFFFFFF) { + h->channels = 1; + h->codec = DUMMY; + break; + } + /* pre-info */ stream_name_size = read_u64(info_offset+0x00,sf); stream_name_offset = info_offset + 0x08; @@ -1115,8 +1140,11 @@ static bool process_data(STREAMFILE* sf, bnk_header_t* h) { stream_name_size = STREAM_NAME_SIZE; read_string(h->stream_name, stream_name_size, stream_name_offset, sf); - /* the stream name likely has to be hashed and that can be used to find the appropeiate ZLSD entry */ - //if (read_u32(info_offset + 0x0c, sf) != 0x01) break; + if (read_u32(info_offset + 0x0c, sf) != 0x01) { + h->channels = 1; + h->codec = EXTERNAL; + break; + } info_offset += 0x18; @@ -1169,13 +1197,19 @@ fail: return false; } -/* zlsd part: parse extra footer (vox?) data */ +/* zlsd part: parse external stream prefetch data */ static bool process_zlsd(STREAMFILE* sf, bnk_header_t* h) { if (!h->zlsd_offset) 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; + 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; if (read_u32(h->zlsd_offset + 0x00, sf) != get_id32be("DSLZ")) @@ -1199,12 +1233,12 @@ static bool process_zlsd(STREAMFILE* sf, bnk_header_t* h) { goto fail; /* 64-bit entries count? */ /* per entry (for SBlk v0x23) - * 00: crc (not referenced elsewhere) + * 00: fnv1-32 hash of the stream name * 04: stream offset (from this offset) * 08: null (part of offset?) * 0c: stream size * 10: offset/size? - * 14: null */ + * 14/18: null */ /* known streams are standard XVAG (no subsongs) */ /* target_subsong is negative if it's working on SBlk streams */ @@ -1220,16 +1254,17 @@ static bool process_zlsd(STREAMFILE* sf, bnk_header_t* h) { 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")) { - /* maybe also a separate warning if XVAG returns more than 1 subsong? */ vgm_logi("BNK: unsupported ZLSD subfile found (report)\n"); goto fail; } - h->codec = XVAG_ATRAC9; + 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; fail: