diff --git a/src/formats.c b/src/formats.c index 9cac65d9..3b14860f 100644 --- a/src/formats.c +++ b/src/formats.c @@ -532,6 +532,8 @@ static const char* extension_list[] = { "sxd", "sxd2", "sxd3", + "szd1", + "szd3", "tad", "tec", @@ -1402,6 +1404,7 @@ static const meta_info meta_info_list[] = { {meta_ESF, "Eurocom ESF header"}, {meta_ADM3, "Crankcase ADM3 header"}, {meta_TT_AD, "Traveller's Tales AUDIO_DATA header"}, + {meta_SNDZ, "Sony SNDZ header"}, }; void get_vgmstream_coding_description(VGMSTREAM* vgmstream, char* out, size_t out_size) { diff --git a/src/libvgmstream.vcxproj b/src/libvgmstream.vcxproj index 8d726ff4..5830c79d 100644 --- a/src/libvgmstream.vcxproj +++ b/src/libvgmstream.vcxproj @@ -551,6 +551,7 @@ + diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters index f224c445..64d9839c 100644 --- a/src/libvgmstream.vcxproj.filters +++ b/src/libvgmstream.vcxproj.filters @@ -1120,6 +1120,9 @@ meta\Source Files + + meta\Source Files + meta\Source Files diff --git a/src/meta/meta.h b/src/meta/meta.h index f423926f..2cd3b917 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -991,4 +991,6 @@ VGMSTREAM* init_vgmstream_tt_ad(STREAMFILE* sf); VGMSTREAM* init_vgmstream_bw_mp3_riff(STREAMFILE* sf); VGMSTREAM* init_vgmstream_bw_riff_mp3(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_sndz(STREAMFILE* sf); + #endif /*_META_H*/ diff --git a/src/meta/sndz.c b/src/meta/sndz.c new file mode 100644 index 00000000..67432b8e --- /dev/null +++ b/src/meta/sndz.c @@ -0,0 +1,170 @@ +#include "meta.h" +#include "../coding/coding.h" + + +/* SNDZ - Sony/SCE's lib? (cousin of SXD) [Gran Turismo 7 (PS4)] */ +VGMSTREAM* init_vgmstream_sndz(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + STREAMFILE* sf_b = NULL; + uint32_t stream_offset, stream_size, name_offset, head_size, data_size; + int channels, loop_flag, sample_rate, codec, streamed; + int32_t num_samples, loop_start, loop_end; + uint32_t at9_config; + uint32_t offset; + int total_subsongs, target_subsong = sf->stream_index; + + + if (!is_id32be(0x00, sf, "SNDZ")) + goto fail; + head_size = read_u32le(0x04, sf); + data_size = read_u32le(0x08, sf); + /* 0x0c: version? (0x00010001) */ + /* 0x10: size size? */ + /* 0x14: null */ + /* 0x18/1c: some kind of ID? (shared by some files) */ + /* 0x20: bank name */ + + + /* .szd1: header + .szd2 = data + * .szd3: szd1 + szd2 */ + if (!check_extensions(sf, "szd1,szd3")) + goto fail; + + /* parse chunk table and WAVS with offset to offset to WAVD */ + { + uint32_t wavs_offset; + int i, entries; + + offset = 0x70; + offset += read_u32le(offset, sf); + + entries = read_u32le(offset, sf); + offset += 0x04; + + wavs_offset = 0; + for (i = 0; i < entries; i ++) { + if (is_id32be(offset + 0x00, sf, "WAVS")) { + /* 0x04: size? */ + wavs_offset = read_u32le(offset + 0x08, sf); + offset += 0x0c; + break; + } + + offset += 0x0c; + } + + if (!wavs_offset) + goto fail; + offset += wavs_offset; + + offset += read_u32le(offset, sf); + } + + /* parse WAVD header */ + { + uint32_t entry_size; + + if (!is_id32be(offset + 0x00, sf, "WAVD")) + goto fail; + entry_size = read_u32le(offset + 0x04, sf); + total_subsongs = read_u32le(offset + 0x08, sf); + + if (target_subsong == 0) target_subsong = 1; + if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail; + + offset += 0x0c; + offset += entry_size * (target_subsong - 1); + + /* main header */ + streamed = read_u32le(offset + 0x00, sf); + name_offset = read_u32le(offset + 0x04, sf) + offset + 0x04; /* from here */ + /* 08: null */ + /* 0c: size/offset? */ + codec = read_u8(offset + 0x10, sf); + channels = read_u8(offset + 0x11, sf); + /* 12: null */ + sample_rate = read_u32le(offset + 0x14, sf); + num_samples = read_s32le(offset + 0x18, sf); + at9_config = read_u32le(offset + 0x1c, sf); + loop_start = read_s32le(offset + 0x20, sf); + loop_end = read_s32le(offset + 0x24, sf); + stream_size = read_u32le(offset + 0x28, sf); /* from data start in szd2 or absolute in szd3 */ + stream_offset = read_u32le(offset + 0x2c, sf); + /* rest: null */ + + loop_flag = loop_end > 0; + } + +VGM_LOG("%i, %x, %x, %x\n", streamed, head_size, data_size, get_streamfile_size(sf)); + /* szd3 is streamed but has header+data together, with padding between (data_size is the same as file size)*/ + if (streamed && get_streamfile_size(sf) < data_size) { + sf_b = open_streamfile_by_ext(sf, "szd2"); + if (!sf_b) { + vgm_logi("SNDZ: can't find companion .szd2 file\n"); + goto fail; + } + + if (data_size > get_streamfile_size(sf_b)) + goto fail; + } + else { + /* should have enough data */ + if (stream_offset + stream_size > get_streamfile_size(sf)) + goto fail; + sf_b = sf; + } + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channels, loop_flag); + if (!vgmstream) goto fail; + + vgmstream->meta_type = meta_SNDZ; + vgmstream->sample_rate = sample_rate; + + vgmstream->num_samples = num_samples; + vgmstream->loop_start_sample = loop_start; + vgmstream->loop_end_sample = loop_end; + + vgmstream->num_streams = total_subsongs; + vgmstream->stream_size = stream_size; + if (name_offset) + read_string(vgmstream->stream_name,STREAM_NAME_SIZE, name_offset, sf); + + switch (codec) { + case 0x20: + vgmstream->coding_type = coding_HEVAG; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x10; + break; + +#ifdef VGM_USE_ATRAC9 + case 0x21: { + atrac9_config cfg = {0}; + + cfg.channels = channels; + cfg.config_data = at9_config; + + vgmstream->codec_data = init_atrac9(&cfg); + if (!vgmstream->codec_data) goto fail; + vgmstream->coding_type = coding_ATRAC9; + vgmstream->layout_type = layout_none; + break; + } +#endif + default: + vgm_logi("SNDZ: unknown codec 0x%x\n", codec); + goto fail; + } + + if (!vgmstream_open_stream(vgmstream, sf_b, stream_offset)) + goto fail; + + if (sf_b != sf) close_streamfile(sf_b); + return vgmstream; + +fail: + if (sf_b != sf) close_streamfile(sf_b); + close_vgmstream(vgmstream); + return NULL; +} diff --git a/src/vgmstream.c b/src/vgmstream.c index 7a989561..33dd336f 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -526,6 +526,7 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = { init_vgmstream_tt_ad, init_vgmstream_bw_mp3_riff, init_vgmstream_bw_riff_mp3, + init_vgmstream_sndz, /* lower priority metas (no clean header identity, somewhat ambiguous, or need extension/companion file to identify) */ init_vgmstream_agsc, diff --git a/src/vgmstream.h b/src/vgmstream.h index 06ff5297..62f7767a 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -762,6 +762,7 @@ typedef enum { meta_ESF, meta_ADM3, meta_TT_AD, + meta_SNDZ, } meta_t;