From 55a0b2082a9c5cb80faaac4137d43760ac5c2560 Mon Sep 17 00:00:00 2001 From: EdnessP <55930127+EdnessP@users.noreply.github.com> Date: Wed, 28 Jun 2023 14:20:47 +0300 Subject: [PATCH] RWS 0x809: DSP-ADPCM and reworked stuff --- src/meta/awd.c | 8 +++---- src/meta/meta.h | 2 +- src/meta/rws_mono.c | 58 +++++++++++++++++++++++++++++---------------- src/vgmstream.c | 2 +- 4 files changed, 43 insertions(+), 27 deletions(-) diff --git a/src/meta/awd.c b/src/meta/awd.c index f20f75e6..29591db9 100644 --- a/src/meta/awd.c +++ b/src/meta/awd.c @@ -29,7 +29,7 @@ VGMSTREAM* init_vgmstream_awd(STREAMFILE* sf) { data_offset = read_u32(0x08, sf); wavedict_offset = read_u32(0x0C, sf); - //data_size = read_u32(0x14, sf); + //data_size = read_u32(0x14, sf); /* Platform UUIDs in big endian * {FD9D32D3-E179-426A-8424-14720AC7F648}: GameCube * {ACC9EAAA-38FC-1749-AE81-64EADBC79353}: PlayStation 2 @@ -72,20 +72,20 @@ VGMSTREAM* init_vgmstream_awd(STREAMFILE* sf) { /* is at the correct target song index */ if (total_subsongs == target_subsong) { - //entry_uuid_offset = read_u32(entry_info_offset + 0x00, sf); /* only used in Burnout games */ + //entry_uuid_offset = read_u32(entry_info_offset + 0x00, sf); /* only used in Burnout games */ entry_name_offset = read_u32(entry_info_offset + 0x04, sf); sample_rate = read_u32(entry_info_offset + 0x10, sf); stream_codec = read_u32(entry_info_offset + 0x14, sf); stream_size = read_u32(entry_info_offset + 0x18, sf); - //bit_depth = read_u8(entry_info_offset + 0x1C, sf); + //bit_depth = read_u8(entry_info_offset + 0x1C, sf); channels = read_u8(entry_info_offset + 0x1D, sf); /* always 1, don't think stereo entries exist */ if (channels != 1) goto fail; /* stores a "00: GCN ADPCM Header" chunk, otherwise empty */ misc_data_offset = read_u32(entry_info_offset + 0x20, sf); - //misc_data_size = read_u32(entry_info_offset + 0x24, sf); + //misc_data_size = read_u32(entry_info_offset + 0x24, sf); /* entry_info_offset + 0x2C to +0x44 has the target format information, * which in most cases would probably be identical to the input format diff --git a/src/meta/meta.h b/src/meta/meta.h index 18cae8af..a6a9fd93 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -980,7 +980,7 @@ VGMSTREAM* init_vgmstream_ego_dic(STREAMFILE* sf); VGMSTREAM* init_vgmstream_awd(STREAMFILE* sf); -VGMSTREAM* init_vgmstream_rws_mono(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_rws_809(STREAMFILE* sf); VGMSTREAM* init_vgmstream_pwb(STREAMFILE* sf); diff --git a/src/meta/rws_mono.c b/src/meta/rws_mono.c index ea88ccf5..33baea63 100644 --- a/src/meta/rws_mono.c +++ b/src/meta/rws_mono.c @@ -4,27 +4,27 @@ /* RWS - RenderWare Stream (with the tag 0x809) */ -VGMSTREAM* init_vgmstream_rws_mono(STREAMFILE* sf) { +VGMSTREAM* init_vgmstream_rws_809(STREAMFILE* sf) { VGMSTREAM* vgmstream = NULL; bool big_endian; char header_name[STREAM_NAME_SIZE], stream_name[STREAM_NAME_SIZE]; - int bit_depth = 0, channels = 0, idx, interleave, loop_flag, sample_rate = 0, total_subsongs, target_subsong = sf->stream_index; + int channels = 0, idx, interleave, loop_flag, sample_rate = 0, total_subsongs, target_subsong = sf->stream_index; read_u32_t read_u32; - off_t chunk_offset, header_offset, stream_offset = 0; - size_t chunk_size, header_size, stream_size = 0; + off_t chunk_offset, header_offset, misc_data_offset = 0, stream_name_offset, stream_offset = 0; + size_t chunk_size, header_size, misc_data_size, stream_size = 0; + uint32_t codec_uuid = 0; /* checks */ if (read_u32le(0x00, sf) != 0x809) /* File ID */ goto fail; - /* Burnout 2: Point of Impact (PS2, GCN, Xbox): - * Predecessor to the common 0x80D-0x80F tag rws.c (which is also used in B2) - * with some parts of it later reworked into awd.c seemingly */ + /* Burnout 2: Point of Impact (PS2, GCN, Xbox), Neighbours from Hell (GCN, Xbox): + * Predecessor to the common 0x80D-0x80F tag RWS with some parts reworked into AWD? */ if (!check_extensions(sf, "rws")) goto fail; - /* Uses various chunk IDs across the file: + /* Uses the following chunk IDs across the file: * 0x00000809: File ID * 0x0000080A: File header ID * 0x0000080C: File data ID @@ -63,19 +63,27 @@ VGMSTREAM* init_vgmstream_rws_mono(STREAMFILE* sf) { header_offset = chunk_offset + 0x0C; if (read_u32le(header_offset, sf) != 0x803) /* Stream header ID */ goto fail; - header_size = read_u32le(header_offset + 0x04, sf); /* usually 0xA0 */ + header_size = read_u32le(header_offset + 0x04, sf); sample_rate = read_u32(header_offset + 0x10, sf); stream_size = read_u32(header_offset + 0x18, sf); - bit_depth = read_u8(header_offset + 0x1C, sf); + //bit_depth = read_u8(header_offset + 0x1C, sf); channels = read_u8(header_offset + 0x1D, sf); /* always 1? */ if (channels != 1) goto fail; - /* Assumed misc data offs/size at header_offset + 0x20 to +0x24 - * which is always empty since GCN uses PCM S16BE encoding here */ + //misc_data_offset = read_u32(header_offset + 0x20, sf); /* assumed, but wrong? */ + misc_data_offset = header_offset + 0x3C; + misc_data_size = read_u32(header_offset + 0x24, sf); /* 0x60 in GCN if DSP-ADPCM, otherwise 0 */ - read_string(stream_name, STREAM_NAME_SIZE, header_offset + 0x7C, sf); + codec_uuid = read_u32(header_offset + 0x2C, sf); + + /* (header_offset + 0x3C + misc_data_size) + 0x00 to +0x18 has the target format + * info which in most cases would probably be identical to the input format info */ + + /* misc_data_size * 2 should be 0xC0 if it exists */ + stream_name_offset = header_offset + 0x7C + (misc_data_size * 2); + read_string(stream_name, STREAM_NAME_SIZE, stream_name_offset, sf); stream_offset = header_offset + header_size + 0x0C; if (read_u32le(stream_offset, sf) != 0x804) /* Stream data ID */ @@ -104,19 +112,27 @@ VGMSTREAM* init_vgmstream_rws_mono(STREAMFILE* sf) { vgmstream->num_streams = total_subsongs; vgmstream->interleave_block_size = interleave; - /* Likely unreliable, but currently only can be tested with Burnout 2 */ - switch (bit_depth) { - case 4: /* PS-ADPCM, normally DSP-ADPCM would be 4 too (as is in awd.c) but GCN uses PCM */ - vgmstream->num_samples = ps_bytes_to_samples(stream_size, channels); - vgmstream->coding_type = coding_PSX; - break; - - case 16: /* PCM Signed 16-bit */ + /* Seems to be the same as in rws.c, maybe merge the two switches into one function? */ + switch (codec_uuid) { + case 0xD01BD217: /* {D01BD217-3587-4EED-B9D9-B8E86EA9B995}: PCM Signed 16-bit */ vgmstream->num_samples = pcm16_bytes_to_samples(stream_size, channels); vgmstream->coding_type = big_endian ? coding_PCM16BE : coding_PCM16LE; break; + case 0xD9EA9798: /* {D9EA9798-BBBC-447B-96B2-654759102E16}: PSX-ADPCM */ + vgmstream->num_samples = ps_bytes_to_samples(stream_size, channels); + vgmstream->coding_type = coding_PSX; + break; + + case 0xF86215B0: /* {F86215B0-31D5-4C29-BD37-CDBF9BD10C53}: DSP-ADPCM */ + vgmstream->num_samples = dsp_bytes_to_samples(stream_size, channels); + dsp_read_coefs_be(vgmstream, sf, misc_data_offset + 0x1C, 0); + dsp_read_hist_be(vgmstream, sf, misc_data_offset + 0x40, 0); + vgmstream->coding_type = coding_NGC_DSP; + break; + default: + VGM_LOG("RWS: unknown codec 0x%08x\n", codec_uuid); goto fail; } diff --git a/src/vgmstream.c b/src/vgmstream.c index fad5ff55..f864a90b 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -521,8 +521,8 @@ init_vgmstream_t init_vgmstream_functions[] = { init_vgmstream_s_p_sth, init_vgmstream_utf_ahx, init_vgmstream_ego_dic, - init_vgmstream_rws_mono, init_vgmstream_awd, + init_vgmstream_rws_809, init_vgmstream_pwb, /* lower priority metas (no clean header identity, somewhat ambiguous, or need extension/companion file to identify) */