diff --git a/doc/TXTH.md b/doc/TXTH.md index d83aa6f9..776bda70 100644 --- a/doc/TXTH.md +++ b/doc/TXTH.md @@ -9,6 +9,10 @@ When an unsupported file is loaded (for instance "bgm01.snd"), vgmstream tries t If found and parsed correctly (the TXTH may be rejected if incorrect commands are found) vgmstream will try to play the file as described. Extension must be accepted/added to vgmstream (plugins like foobar2000 only load extensions from a whitelist in formats.c), or one could rename to any supported extension (like .vgmstream), or leave the file extensionless. +You can also use ".(sub).(ext).txth" (if the file is "filename.sub.ext"), to allow mixing slightly different files in the same folder. The "sub" part doesn't need to be an extension, for example: +- 001.1ch.str, 001.1ch.str may use .1ch.txth +- 003.2ch.str, 003.2ch.str may use .2ch.txth +- etc ## Example of a TXTH file For an unsupported bgm01.vag this would be a simple TXTH for it: @@ -82,6 +86,7 @@ A text file with the above commands must be saved as ".vag.txth" or ".txth", not # - PCFX PC-FX ADPCM # - PCM4 PCM 4-bit signed # - PCM4_U PCM 4-bit unsigned +# - OKI16 OKI ADPCM with 16-bit output (not std/VOX/Dialogic 12-bit) codec = (codec string) # Codec variations [OPTIONAL, depends on codec] diff --git a/src/coding/coding.h b/src/coding/coding.h index 3744232a..fdf3fa0f 100644 --- a/src/coding/coding.h +++ b/src/coding/coding.h @@ -101,7 +101,8 @@ void decode_ea_xa_v2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspac void decode_maxis_xa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); /* ea_xas_decoder */ -void decode_ea_xas(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); +void decode_ea_xas_v0(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); +void decode_ea_xas_v1(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); /* sdx2_decoder */ void decode_sdx2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); @@ -170,9 +171,10 @@ void decode_derf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, /* circus_decoder */ void decode_circus_adpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); -/* pcfx_decoder */ +/* oki_decoder */ void decode_pcfx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int mode); -size_t pcfx_bytes_to_samples(size_t bytes, int channels); +void decode_oki16(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); +size_t oki_bytes_to_samples(size_t bytes, int channels); /* ea_mt_decoder*/ ea_mt_codec_data *init_ea_mt(int channels, int type); @@ -341,6 +343,7 @@ void xma2_parse_fmt_chunk_extra(STREAMFILE *streamFile, off_t chunk_offset, int void xma2_parse_xma2_chunk(STREAMFILE *streamFile, off_t chunk_offset, int * channels, int * sample_rate, int * loop_flag, int32_t * num_samples, int32_t * loop_start_sample, int32_t * loop_end_sample); void xma_fix_raw_samples(VGMSTREAM *vgmstream, STREAMFILE*streamFile, off_t stream_offset, size_t stream_size, off_t chunk_offset, int fix_num_samples, int fix_loop_samples); +void xma_fix_raw_samples_ch(VGMSTREAM *vgmstream, STREAMFILE*streamFile, off_t stream_offset, size_t stream_size, int channel_per_stream, int fix_num_samples, int fix_loop_samples); int riff_get_fact_skip_samples(STREAMFILE * streamFile, off_t start_offset); diff --git a/src/coding/coding_utils.c b/src/coding/coding_utils.c index 8b601ccd..2b464a35 100644 --- a/src/coding/coding_utils.c +++ b/src/coding/coding_utils.c @@ -799,14 +799,13 @@ void wma_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, int block_ali /* XMA hell for precise looping and gapless support, fixes raw sample values from headers * that don't count XMA's final subframe/encoder delay/encoder padding, and FFmpeg stuff. * Configurable since different headers vary for maximum annoyance. */ -void xma_fix_raw_samples(VGMSTREAM *vgmstream, STREAMFILE*streamFile, off_t stream_offset, size_t stream_size, off_t chunk_offset, int fix_num_samples, int fix_loop_samples) { +void xma_fix_raw_samples_ch(VGMSTREAM *vgmstream, STREAMFILE*streamFile, off_t stream_offset, size_t stream_size, int channels_per_stream, int fix_num_samples, int fix_loop_samples) { const int bytes_per_packet = 2048; const int samples_per_frame = 512; const int samples_per_subframe = 128; const int bits_frame_size = 15; int xma_version = 2; /* works ok even for XMA1 */ - int channels_per_stream = xma_get_channels_per_stream(streamFile, chunk_offset, vgmstream->channels); off_t first_packet = stream_offset; off_t last_packet = stream_offset + stream_size - bytes_per_packet; int32_t start_skip = 0, end_skip = 0; @@ -872,6 +871,12 @@ void xma_fix_raw_samples(VGMSTREAM *vgmstream, STREAMFILE*streamFile, off_t stre #endif } +void xma_fix_raw_samples(VGMSTREAM *vgmstream, STREAMFILE*streamFile, off_t stream_offset, size_t stream_size, off_t chunk_offset, int fix_num_samples, int fix_loop_samples) { + int channels_per_stream = xma_get_channels_per_stream(streamFile, chunk_offset, vgmstream->channels); + xma_fix_raw_samples_ch(vgmstream, streamFile, stream_offset, stream_size, channels_per_stream, fix_num_samples, fix_loop_samples); +} + + /* ******************************************** */ /* HEADER PARSING */ /* ******************************************** */ diff --git a/src/coding/ea_xas_decoder.c b/src/coding/ea_xas_decoder.c index 148bfff8..e28c6c8c 100644 --- a/src/coding/ea_xas_decoder.c +++ b/src/coding/ea_xas_decoder.c @@ -9,11 +9,11 @@ static const int EA_XA_TABLE[20] = { 0, -1, -3, -4 }; -/* EA-XAS, evolution of EA-XA and cousin of MTA2. From FFmpeg (general info) + MTA2 (layout) + EA-XA (decoding) +/* EA-XAS v1, evolution of EA-XA/XAS and cousin of MTA2. From FFmpeg (general info) + MTA2 (layout) + EA-XA (decoding) * * Layout: blocks of 0x4c per channel (128 samples), divided into 4 headers + 4 vertical groups of 15 bytes (for parallelism?). * To simplify, always decodes the block and discards unneeded samples, so doesn't use external hist. */ -void decode_ea_xas(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) { +void decode_ea_xas_v1(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) { int group, row, i; int samples_done = 0, sample_count = 0; @@ -77,3 +77,64 @@ void decode_ea_xas(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacin stream->offset += 0x4c * channelspacing; } } + + +/* EA-XAS v0, without complex layouts and closer to EA-XA. Somewhat based on daemon1's decoder */ +void decode_ea_xas_v0(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) { + off_t frame_offset; + int i; + int block_samples, frames_in, samples_done = 0, sample_count = 0; + + /* external interleave (fixed size), mono */ + block_samples = 32; + frames_in = first_sample / block_samples; + first_sample = first_sample % block_samples; + + frame_offset = stream->offset + (0x0f+0x02+0x02)*frames_in; + + /* process frames */ + { + int coef1, coef2; + int16_t hist1, hist2; + uint8_t shift; + uint32_t frame_header = (uint32_t)read_32bitLE(frame_offset, stream->streamfile); /* always LE */ + + coef1 = EA_XA_TABLE[(uint8_t)(frame_header & 0x0F) + 0]; + coef2 = EA_XA_TABLE[(uint8_t)(frame_header & 0x0F) + 4]; + hist2 = (int16_t)(frame_header & 0xFFF0); + hist1 = (int16_t)((frame_header >> 16) & 0xFFF0); + shift = 20 - ((frame_header >> 16) & 0x0F); + + /* write header samples (needed) */ + if (sample_count >= first_sample && samples_done < samples_to_do) { + outbuf[samples_done * channelspacing] = hist2; + samples_done++; + } + sample_count++; + if (sample_count >= first_sample && samples_done < samples_to_do) { + outbuf[samples_done * channelspacing] = hist1; + samples_done++; + } + sample_count++; + + /* process nibbles */ + for (i = 0; i < 0x0f*2; i++) { + uint8_t sample_byte = (uint8_t)read_8bit(frame_offset + 0x02 + 0x02 + i/2, stream->streamfile); + int sample; + + sample = get_nibble_signed(sample_byte, !(i&1)); /* upper first */ + sample = sample << shift; + sample = (sample + hist1 * coef1 + hist2 * coef2 + 128) >> 8; + sample = clamp16(sample); + + if (sample_count >= first_sample && samples_done < samples_to_do) { + outbuf[samples_done * channelspacing] = sample; + samples_done++; + } + sample_count++; + + hist2 = hist1; + hist1 = sample; + } + } +} diff --git a/src/coding/pcfx_decoder.c b/src/coding/oki_decoder.c similarity index 55% rename from src/coding/pcfx_decoder.c rename to src/coding/oki_decoder.c index 63cac856..9f39566a 100644 --- a/src/coding/pcfx_decoder.c +++ b/src/coding/oki_decoder.c @@ -1,14 +1,14 @@ #include "coding.h" -static const int step_sizes[49] = { /* OKI table */ +static const int step_sizes[49] = { /* OKI table (subsection of IMA's table) */ 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552 }; -static const int stex_indexes[16] = { /* IMA table */ +static const int stex_indexes[16] = { /* OKI table (also from IMA) */ -1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8 }; @@ -54,6 +54,26 @@ static void pcfx_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, int } } +static void oki16_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, int nibble_shift, int32_t * hist1, int32_t * step_index, int16_t *out_sample) { + int code, step, delta; + + code = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift) & 0xf; + step = step_sizes[*step_index]; + + delta = (code & 0x7); + delta = (((delta * 2) + 1) * step) >> 3; /* IMA 'mul' style (standard OKI uses 'shift-add') */ + if (code & 0x8) + delta = -delta; + *hist1 += delta; + + /* standard OKI clamps hist to 2047,-2048 here */ + + *step_index += stex_indexes[code]; + if (*step_index < 0) *step_index = 0; + if (*step_index > 48) *step_index = 48; + + *out_sample = *hist1; +} /* PC-FX ADPCM decoding, variation of OKI/Dialogic/VOX ADPCM. Based on mednafen/pcfx-music-dump. * Apparently most ADPCM was made with a buggy encoder, resulting in incorrect sound in real hardware @@ -65,7 +85,7 @@ static void pcfx_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, int * * PC-FX ISOs don't have a standard filesystem nor file formats (raw data must be custom-ripped), * so it's needs GENH/TXTH. Sample rate can only be base_value divided by 1/2/3/4, where - * base_value is approximately ~31468.5 (follows hardware clocks), mono or stereo-interleaved. + * base_value is approximately ~31468.5 (follows hardware clocks), mono or interleaved for stereo. */ void decode_pcfx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int mode) { int i, sample_count = 0; @@ -86,7 +106,40 @@ void decode_pcfx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, stream->adpcm_step_index = step_index; } -size_t pcfx_bytes_to_samples(size_t bytes, int channels) { +/* OKI variation with 16-bit output (vs standard's 12-bit), found in FrontWing's PS2 games (Sweet Legacy, Hooligan). + * Reverse engineered from the ELF with help from the folks at hcs. */ +void decode_oki16(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) { + int i, sample_count = 0; + int32_t hist1 = stream->adpcm_history1_32; + int step_index = stream->adpcm_step_index; + int16_t out_sample; + int is_stereo = channelspacing > 1; + + + /* external interleave */ + + /* no header (external setup), pre-clamp for wrong values */ + if (step_index < 0) step_index=0; + if (step_index > 48) step_index=48; + + /* decode nibbles (layout: varies) */ + for (i = first_sample; i < first_sample + samples_to_do; i++, sample_count += channelspacing) { + off_t byte_offset = is_stereo ? + stream->offset + i : /* stereo: one nibble per channel */ + stream->offset + i/2; /* mono: consecutive nibbles (assumed) */ + int nibble_shift = + is_stereo ? (!(channel&1) ? 0:4) : (!(i&1) ? 0:4); /* even = low, odd = high */ + + oki16_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index, &out_sample); + outbuf[sample_count] = (out_sample); + } + + stream->adpcm_history1_32 = hist1; + stream->adpcm_step_index = step_index; +} + + +size_t oki_bytes_to_samples(size_t bytes, int channels) { /* 2 samples per byte (2 nibbles) in stereo or mono config */ return bytes * 2 / channels; } diff --git a/src/formats.c b/src/formats.c index 89416187..26a29a78 100644 --- a/src/formats.c +++ b/src/formats.c @@ -155,6 +155,7 @@ static const char* extension_list[] = { "gcub", "gcw", "genh", + "gin", "gms", "gsb", //"gsf", //conflicts with GBA gsf plugins? @@ -194,7 +195,7 @@ static const char* extension_list[] = { "kces", "kcey", //fake extension/header id for .pcm (renamed, to be removed) - "khv", + "khv", //fake extension/header id for .vas (renamed, to be removed) "km9", "kovs", //fake extension/header id for .kvs "kns", @@ -586,7 +587,8 @@ static const coding_info coding_info_list[] = { {coding_EA_XA_int, "Electronic Arts EA-XA 4-bit ADPCM v1 (mono/interleave)"}, {coding_EA_XA_V2, "Electronic Arts EA-XA 4-bit ADPCM v2"}, {coding_MAXIS_XA, "Maxis EA-XA 4-bit ADPCM"}, - {coding_EA_XAS, "Electronic Arts EA-XAS 4-bit ADPCM"}, + {coding_EA_XAS_V0, "Electronic Arts EA-XAS 4-bit ADPCM v0"}, + {coding_EA_XAS_V1, "Electronic Arts EA-XAS 4-bit ADPCM v1"}, {coding_IMA, "IMA 4-bit ADPCM"}, {coding_IMA_int, "IMA 4-bit ADPCM (mono/interleave)"}, @@ -633,6 +635,7 @@ static const coding_info coding_info_list[] = { {coding_ASF, "Argonaut ASF 4-bit ADPCM"}, {coding_XMD, "Konami XMD 4-bit ADPCM"}, {coding_PCFX, "PC-FX 4-bit ADPCM"}, + {coding_OKI16, "OKI 4-bit ADPCM (16-bit output)"}, {coding_SDX2, "Squareroot-delta-exact (SDX2) 8-bit DPCM"}, {coding_SDX2_int, "Squareroot-delta-exact (SDX2) 8-bit DPCM with 1 byte interleave"}, @@ -995,7 +998,7 @@ static const meta_info meta_info_list[] = { {meta_PS3_CPS, "tri-Crescendo CPS Header"}, {meta_SQEX_SCD, "Square-Enix SCD header"}, {meta_NGC_NST_DSP, "Animaniacs NST header"}, - {meta_BAF, ".baf WAVE header"}, + {meta_BAF, "Bizarre Creations .baf header"}, {meta_PS3_MSF, "Sony MSF header"}, {meta_NUB_VAG, "Namco NUB VAG header"}, {meta_PS3_PAST, "SNDP header"}, @@ -1155,6 +1158,7 @@ static const meta_info meta_info_list[] = { {meta_DSP_ADPCMX, "AQUASTYLE ADPY header"}, {meta_OGG_OPUS, "Ogg Opus header"}, {meta_IMC, "iNiS .IMC header"}, + {meta_GIN, "Electronic Arts Gnsu header"}, }; diff --git a/src/libvgmstream.vcproj b/src/libvgmstream.vcproj index a406a52b..104fec5b 100644 --- a/src/libvgmstream.vcproj +++ b/src/libvgmstream.vcproj @@ -576,10 +576,14 @@ RelativePath=".\meta\gcsw.c" > - - + + + + @@ -1058,10 +1062,6 @@ RelativePath=".\meta\ps2_kces.c" > - - @@ -1887,7 +1887,7 @@ > + @@ -366,7 +367,6 @@ - @@ -526,7 +526,7 @@ - + diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters index 25c27c0e..dbceedc8 100644 --- a/src/libvgmstream.vcxproj.filters +++ b/src/libvgmstream.vcxproj.filters @@ -364,6 +364,9 @@ meta\Source Files + + meta\Source Files + meta\Source Files @@ -655,9 +658,6 @@ meta\Source Files - - meta\Source Files - meta\Source Files @@ -1117,7 +1117,7 @@ coding\Source Files - + coding\Source Files diff --git a/src/meta/baf.c b/src/meta/baf.c index dff1503f..80308a4f 100644 --- a/src/meta/baf.c +++ b/src/meta/baf.c @@ -1,9 +1,189 @@ #include "meta.h" +#include "../coding/coding.h" -/* .BAF - Bizarre Creations (Blur, James Bond 007: Blood Stone, etc) */ + +/* .BAF - Bizarre Creations bank file [Blur (PS3), Project Gotham Racing 4 (X360), Geometry Wars (PC)] */ VGMSTREAM * init_vgmstream_baf(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - off_t WAVE_size, DATA_size; + off_t start_offset, header_offset, name_offset; + size_t stream_size; + int loop_flag, channel_count, sample_rate, version, codec; + int total_subsongs, target_subsong = streamFile->stream_index; + int32_t (*read_32bit)(off_t,STREAMFILE*); + + + /* checks */ + if (!check_extensions(streamFile, "baf")) + goto fail; + if (read_32bitBE(0x00,streamFile) != 0x42414E4B) /* "BANK" */ + goto fail; + + /* use BANK size to check endianness */ + if (guess_endianness32bit(0x04,streamFile)) { + read_32bit = read_32bitBE; + } else { + read_32bit = read_32bitLE; + } + + /* 0x04: bank size */ + version = read_32bit(0x08,streamFile); + if (version != 0x03 && version != 0x04) + goto fail; + total_subsongs = read_32bit(0x0c,streamFile); + if (target_subsong == 0) target_subsong = 1; + if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail; + /* - in v3 */ + /* 0x10: 0? */ + /* 0x11: bank name */ + /* - in v4 */ + /* 0x10: 1? */ + /* 0x11: padding flag? */ + /* 0x12: bank name */ + + /* find target WAVE chunk */ + { + int i; + off_t offset = read_32bit(0x04, streamFile); + + for (i = 0; i < total_subsongs; i++) { + if (i+1 == target_subsong) + break; + offset += read_32bit(offset+0x04, streamFile); /* WAVE size, variable per codec */ + } + header_offset = offset; + } + + /* parse header */ + if (read_32bitBE(header_offset+0x00, streamFile) != 0x57415645) /* "WAVE" */ + goto fail; + codec = read_32bit(header_offset+0x08, streamFile); + name_offset = header_offset + 0x0c; + start_offset = read_32bit(header_offset+0x2c, streamFile); + stream_size = read_32bit(header_offset+0x30, streamFile); + switch(codec) { + case 0x03: + switch(version) { + case 0x03: /* Geometry Wars (PC) */ + sample_rate = read_32bit(header_offset + 0x38, streamFile); + channel_count = read_32bit(header_offset + 0x40, streamFile); + /* no actual flag, just loop +15sec songs */ + loop_flag = (pcm_bytes_to_samples(stream_size, channel_count, 16) > 15*sample_rate); + break; + + case 0x04: /* Project Gotham Racing 4 (X360) */ + sample_rate = read_32bit(header_offset + 0x3c, streamFile); + channel_count = read_32bit(header_offset + 0x44, streamFile); + loop_flag = read_8bit(header_offset+0x4b, streamFile); + break; + } + break; + + case 0x07: /* Blur (PS3) */ + sample_rate = read_32bit(header_offset+0x40, streamFile); + loop_flag = read_8bit(header_offset+0x48, streamFile); + channel_count = read_8bit(header_offset+0x4b, streamFile); + break; + + case 0x08: /* Project Gotham Racing (X360) */ + sample_rate = read_32bit(header_offset+0x3c, streamFile); + channel_count = read_32bit(header_offset+0x44, streamFile); + loop_flag = read_8bit(header_offset+0x54, streamFile) != 0; + break; + + default: + VGM_LOG("BAF: unknown version %x\n", version); + goto fail; + } + /* others: pan/vol? fixed values? (0x19, 0x10) */ + + /* after WAVEs there may be padding then DATAs chunks, but offsets point after DATA size */ + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + vgmstream->meta_type = meta_BAF; + vgmstream->sample_rate = sample_rate; + vgmstream->num_streams = total_subsongs; + vgmstream->stream_size = stream_size; + + switch(codec) { + case 0x03: + vgmstream->coding_type = coding_PCM16LE; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x02; + + vgmstream->num_samples = pcm_bytes_to_samples(stream_size, channel_count, 16); + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = vgmstream->num_samples; + break; + + case 0x07: + vgmstream->coding_type = coding_PSX_cfg; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x21; + + vgmstream->num_samples = read_32bit(header_offset+0x44, streamFile); + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = vgmstream->num_samples; + break; + + case 0x08: { + uint8_t buf[0x100]; + int bytes; + + bytes = ffmpeg_make_riff_xma1(buf,0x100, vgmstream->num_samples, stream_size, vgmstream->channels, vgmstream->sample_rate, 0); + vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,stream_size); + if (!vgmstream->codec_data) goto fail; + vgmstream->coding_type = coding_FFmpeg; + vgmstream->layout_type = layout_none; + + /* need to manually find sample offsets, it was a thing with XMA1 */ + { + ms_sample_data msd = {0}; + + msd.xma_version = 1; + msd.channels = channel_count; + msd.data_offset = start_offset; + msd.data_size = stream_size; + msd.loop_flag = loop_flag; + msd.loop_start_b = read_32bit(header_offset+0x4c, streamFile); + msd.loop_end_b = read_32bit(header_offset+0x50, streamFile); + msd.loop_start_subframe = (read_8bit(header_offset+0x55, streamFile) >> 0) & 0x0f; + msd.loop_end_subframe = (read_8bit(header_offset+0x55, streamFile) >> 4) & 0x0f; + xma_get_samples(&msd, streamFile); + + vgmstream->num_samples = msd.num_samples; /* also at 0x58, but unreliable? */ + vgmstream->loop_start_sample = msd.loop_start_sample; + vgmstream->loop_end_sample = msd.loop_end_sample; + } + + xma_fix_raw_samples_ch(vgmstream, streamFile, start_offset, stream_size, channel_count, 1,1); + break; + } + + default: + VGM_LOG("BAF: unknown codec %x\n", codec); + goto fail; + } + + read_string(vgmstream->stream_name,0x20+1, name_offset,streamFile); + + + if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} + +/* awful PS3 splits of the above with bad offsets and all */ +VGMSTREAM * init_vgmstream_baf_badrip(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + off_t WAVE_size, stream_size; off_t start_offset; long sample_count; int sample_rate; @@ -13,38 +193,31 @@ VGMSTREAM * init_vgmstream_baf(STREAMFILE *streamFile) { int channels; int loop_flag = 0; - /* check extensions */ + /* checks */ if ( !check_extensions(streamFile, "baf") ) goto fail; - - /* check WAVE */ if (read_32bitBE(0,streamFile) != 0x57415645) /* "WAVE" */ goto fail; WAVE_size = read_32bitBE(4,streamFile); if (WAVE_size != 0x4c) /* && WAVE_size != 0x50*/ goto fail; - /* check for DATA after WAVE */ if (read_32bitBE(WAVE_size,streamFile) != 0x44415441) /* "DATA"*/ goto fail; /* check that WAVE size is data size */ - DATA_size = read_32bitBE(0x30,streamFile); - if (read_32bitBE(WAVE_size+4,streamFile)-8 != DATA_size) goto fail; + stream_size = read_32bitBE(0x30,streamFile); + if (read_32bitBE(WAVE_size+4,streamFile)-8 != stream_size) goto fail; - /*if (WAVE_size == 0x50) sample_count = DATA_size * frame_samples / frame_size / channels;*/ sample_count = read_32bitBE(0x44,streamFile); - - /*if (WAVE_size == 0x50) sample_rate = read_32bitBE(0x3c,streamFile);*/ sample_rate = read_32bitBE(0x40,streamFile); - /* unsure how to detect channel count, so use a hack */ - channels = (long long)DATA_size / frame_size * frame_samples / sample_count; + channels = (long long)stream_size / frame_size * frame_samples / sample_count; + start_offset = WAVE_size + 8; + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channels,loop_flag); if (!vgmstream) goto fail; - /* fill in the vital statistics */ - start_offset = WAVE_size + 8; vgmstream->sample_rate = sample_rate; vgmstream->num_samples = sample_count; @@ -53,14 +226,11 @@ VGMSTREAM * init_vgmstream_baf(STREAMFILE *streamFile) { vgmstream->interleave_block_size = frame_size; vgmstream->meta_type = meta_BAF; - /* open the file for reading */ if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) goto fail; - return vgmstream; fail: close_vgmstream(vgmstream); return NULL; } - diff --git a/src/meta/bnk_sony.c b/src/meta/bnk_sony.c index f7924cf0..b5437b69 100644 --- a/src/meta/bnk_sony.c +++ b/src/meta/bnk_sony.c @@ -3,16 +3,16 @@ typedef enum { PSX, PCM16, ATRAC9, HEVAG } bnk_codec; -/* BNK - Sony's Scream Tool bank format [Puyo Puyo Tetris (PS4), NekoBuro: Cats Block (Vita)] */ +/* .BNK - Sony's Scream Tool bank format [Puyo Puyo Tetris (PS4), NekoBuro: Cats Block (Vita)] */ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) { -#if 1 VGMSTREAM * vgmstream = NULL; off_t start_offset, stream_offset, name_offset = 0; size_t stream_size, interleave = 0; off_t sblk_offset, data_offset; size_t data_size; - int channel_count = 0, loop_flag, sample_rate, parts, version; + int channel_count = 0, loop_flag, sample_rate, parts, version, big_endian; int loop_start = 0, loop_end = 0; + uint32_t pitch, flags; uint32_t atrac9_info = 0; int total_subsongs, target_subsong = streamFile->stream_index; @@ -28,10 +28,12 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) { if (read_32bitBE(0x00,streamFile) == 0x00000003) { /* PS3 */ read_32bit = read_32bitBE; read_16bit = read_16bitBE; + big_endian = 1; } else if (read_32bitBE(0x00,streamFile) == 0x03000000) { /* Vita/PS4 */ read_32bit = read_32bitLE; read_16bit = read_16bitLE; + big_endian = 0; } else { goto fail; @@ -44,11 +46,13 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) { /* 0x0c: sklb size */ data_offset = read_32bit(0x10,streamFile); data_size = read_32bit(0x14,streamFile); + /* when sblk_offset >= 0x20: */ /* 0x18: ZLSD small footer, rare [Yakuza 6's Puyo Puyo (PS4)] */ /* 0x1c: ZLSD size */ /* SE banks, also used for music. Most table fields seems reserved/defaults and - * don't change much between subsongs or files, so they aren't described in detail */ + * don't change much between subsongs or files, so they aren't described in detail. + * Entry sizes are variable (usually flag + extra size xN) so table offsets are needed. */ /* SBlk part: parse header */ @@ -63,7 +67,7 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) { off_t table1_offset, table2_offset, table3_offset, table4_offset; size_t section_entries, material_entries, stream_entries; size_t table1_entry_size; - off_t table1_suboffset, table2_suboffset, table3_suboffset; + off_t table1_suboffset, table2_suboffset; off_t table2_entry_offset = 0, table3_entry_offset = 0; int table4_entry_id = -1; off_t table4_entries_offset, table4_names_offset; @@ -75,7 +79,7 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) { case 0x09: /* Puyo Puyo Tetris (PS4) */ section_entries = (uint16_t)read_16bit(sblk_offset+0x16,streamFile); /* entry size: ~0x0c */ material_entries = (uint16_t)read_16bit(sblk_offset+0x18,streamFile); /* entry size: ~0x08 */ - stream_entries = (uint16_t)read_16bit(sblk_offset+0x1a,streamFile); /* entry size: ~0x60 */ + stream_entries = (uint16_t)read_16bit(sblk_offset+0x1a,streamFile); /* entry size: ~0x18 + variable */ table1_offset = sblk_offset + read_32bit(sblk_offset+0x1c,streamFile); table2_offset = sblk_offset + read_32bit(sblk_offset+0x20,streamFile); table3_offset = sblk_offset + read_32bit(sblk_offset+0x34,streamFile); @@ -84,7 +88,6 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) { table1_entry_size = 0x0c; table1_suboffset = 0x08; table2_suboffset = 0x00; - table3_suboffset = 0x10; break; case 0x0d: /* Polara (Vita), Crypt of the Necrodancer (Vita) */ @@ -95,12 +98,11 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) { table4_offset = sblk_offset + read_32bit(sblk_offset+0x30,streamFile); section_entries = (uint16_t)read_16bit(sblk_offset+0x38,streamFile); /* entry size: ~0x24 */ material_entries = (uint16_t)read_16bit(sblk_offset+0x3a,streamFile); /* entry size: ~0x08 */ - stream_entries = (uint16_t)read_16bit(sblk_offset+0x3c,streamFile); /* entry size: ~0x90 + variable (sometimes) */ + stream_entries = (uint16_t)read_16bit(sblk_offset+0x3c,streamFile); /* entry size: ~0x5c + variable */ table1_entry_size = 0x24; table1_suboffset = 0x0c; table2_suboffset = 0x00; - table3_suboffset = 0x44; break; default: @@ -150,14 +152,64 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) { if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail; /* this means some subsongs repeat streams, that can happen in some sfx banks, whatevs */ if (total_subsongs != stream_entries) { - //;VGM_LOG("BNK: subsongs %i vs table3 %i don't match\n", total_subsongs, stream_entries); + VGM_LOG("BNK: subsongs %i vs table3 %i don't match\n", total_subsongs, stream_entries); /* find_dupes...? */ } + //;VGM_LOG("BNK: header entry at %lx\n", table3_offset+table3_entry_offset); /* parse sounds */ - stream_offset = read_32bit(table3_offset+table3_entry_offset+table3_suboffset+0x00,streamFile); - stream_size = read_32bit(table3_offset+table3_entry_offset+table3_suboffset+0x04,streamFile); + switch(version) { + case 0x03: + case 0x04: + case 0x09: + pitch = (uint8_t)read_8bit(table3_offset+table3_entry_offset+0x02,streamFile); + flags = (uint8_t)read_8bit(table3_offset+table3_entry_offset+0x0f,streamFile); + stream_offset = read_32bit(table3_offset+table3_entry_offset+0x10,streamFile); + stream_size = read_32bit(table3_offset+table3_entry_offset+0x14,streamFile); + + /* must use some log/formula but whatevs */ + switch(pitch) { + case 0xC6: sample_rate = 50000; break; //? + case 0xC4: sample_rate = 48000; break; + case 0xC3: sample_rate = 46000; break; //? + case 0xC2: sample_rate = 44100; break; + case 0xBC: sample_rate = 36000; break; //? + case 0xBA: sample_rate = 32000; break; //? + case 0xB6: sample_rate = 22050; break; + case 0xAA: sample_rate = 11025; break; + default: + VGM_LOG("BNK: unknown pitch %x\n", pitch); + goto fail; + } + break; + + case 0x0d: + case 0x0e: + flags = (uint8_t)read_8bit(table3_offset+table3_entry_offset+0x12,streamFile); + stream_offset = read_32bit(table3_offset+table3_entry_offset+0x44,streamFile); + stream_size = read_32bit(table3_offset+table3_entry_offset+0x48,streamFile); + pitch = (uint32_t)read_32bit(table3_offset+table3_entry_offset+0x4c,streamFile); + + /* this looks like "((pitch >> 9) & 0xC000) | ((pitch >> 8) & 0xFFFF)" but... why??? */ + switch(pitch) { + case 0x467A0000: sample_rate = 64000; break; //? + case 0x46BB8000: sample_rate = 48000; break; + case 0x473B8000: sample_rate = 48000; break; + case 0x46AC4400: sample_rate = 44100; break; + case 0x47AC4400: sample_rate = 44100; break; + case 0x472C4400: sample_rate = 44100; break; + default: + VGM_LOG("BNK: unknown pitch %x\n", pitch); + goto fail; + } + break; + + default: + goto fail; + } + + //;VGM_LOG("BNK: stream at %lx + %x\n", stream_offset, stream_size); /* parse names */ switch(version) { @@ -215,7 +267,6 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) { switch(version) { case 0x03: case 0x04: - sample_rate = 48000; /* seems ok */ channel_count = 1; /* hack for PS3 files that use dual subsongs as stereo */ @@ -224,14 +275,19 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) { stream_size = stream_size*channel_count; total_subsongs = 1; } - interleave = stream_size / channel_count; + + if (flags & 0x80) { + codec = PCM16; /* rare [Wipeout HD (PS3)] */ + } + else { + loop_flag = ps_find_loop_offsets(streamFile, start_offset, stream_size, channel_count, interleave, &loop_start, &loop_end); + loop_flag = (flags & 0x40); /* no loops values in sight so may only apply to PS-ADPCM flags */ + + codec = PSX; + } + //postdata_size = 0x10; /* last frame may be garbage */ - - loop_flag = ps_find_loop_offsets(streamFile, start_offset, stream_size, channel_count, interleave, &loop_start, &loop_end); - loop_flag = (loop_start > 28); /* ignore full loops since they just fadeout + repeat */ - - codec = PSX; break; case 0x09: @@ -243,7 +299,6 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) { case 0x05: /* ATRAC9 stereo */ if (read_32bit(start_offset+0x08,streamFile) + 0x08 != extradata_size) /* repeat? */ goto fail; - sample_rate = 48000; /* seems ok */ channel_count = (type == 0x02) ? 1 : 2; atrac9_info = (uint32_t)read_32bitBE(start_offset+0x0c,streamFile); @@ -274,7 +329,6 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) { case 0x05: /* ATRAC9 stereo */ if (read_32bit(start_offset+0x10,streamFile) + 0x10 != extradata_size) /* repeat? */ goto fail; - sample_rate = 48000; /* seems ok */ channel_count = (type == 0x02) ? 1 : 2; atrac9_info = (uint32_t)read_32bitBE(start_offset+0x14,streamFile); @@ -291,7 +345,6 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) { case 0x01: /* PCM16LE mono? (NekoBuro/Polara sfx) */ case 0x04: /* PCM16LE stereo? (NekoBuro/Polara sfx) */ - sample_rate = 48000; /* seems ok */ /* 0x10: null? */ channel_count = read_32bit(start_offset+0x14,streamFile); interleave = 0x02; @@ -304,7 +357,6 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) { break; case 0x00: /* PS-ADPCM (test banks) */ - sample_rate = 48000; /* seems ok */ /* 0x10: null? */ channel_count = read_32bit(start_offset+0x14,streamFile); interleave = 0x02; @@ -366,7 +418,7 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) { } #endif case PCM16: - vgmstream->coding_type = coding_PCM16LE; + vgmstream->coding_type = big_endian ? coding_PCM16BE : coding_PCM16LE; vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = interleave; @@ -376,7 +428,6 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) { break; case PSX: - vgmstream->sample_rate = 48000; vgmstream->coding_type = coding_PSX; vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = interleave; @@ -387,7 +438,6 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) { break; case HEVAG: - vgmstream->sample_rate = 48000; vgmstream->coding_type = coding_HEVAG; vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = interleave; @@ -410,6 +460,22 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) { return vgmstream; fail: close_vgmstream(vgmstream); -#endif return NULL; } + + +#if 0 +/* .BNK - Sony's bank, earlier version [Jak and Daxter (PS2), NCAA Gamebreaker 2001 (PS2)] */ +VGMSTREAM * init_vgmstream_bnk_sony_v2(STREAMFILE *streamFile) { + /* 0x00: 0x00000001 + * 0x04: sections (2 or 3) + * 0x08+ similar to v3 but "SBv2" + * table formats is a bit different + * header is like v3 but stream size is in other table? + */ + +fail: + close_vgmstream(vgmstream); + return NULL; +} +#endif diff --git a/src/meta/ea_eaac.c b/src/meta/ea_eaac.c index 21b90568..767f5794 100644 --- a/src/meta/ea_eaac.c +++ b/src/meta/ea_eaac.c @@ -121,7 +121,7 @@ VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE *streamFile) { } header_offset = 0x10; /* SNR header */ - start_offset = read_32bit(0x08,streamFile); /* SPS blocks */ + start_offset = read_32bit(0x08,streamFile); /* SNS blocks */ vgmstream = init_vgmstream_eaaudiocore_header(streamFile, streamFile, header_offset, start_offset, meta_EA_SNU); if (!vgmstream) goto fail; @@ -583,6 +583,15 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST VGM_LOG("EA EAAC: unknown actual looping for codec %x\n", eaac.codec); goto fail; } + + if (eaac.version == EAAC_VERSION_V0) { + /* SNR+SNS are separate so offsets are relative to the data start + * (first .SNS block, or extra data before the .SNS block in case of .SNU) */ + eaac.loop_offset = eaac.stream_offset + eaac.loop_offset; + } else { + /* SPS have headers+data together so offsets are relative to the file start [ex. FIFA 18 (PC)] */ + eaac.loop_offset = header_offset - 0x04 + eaac.loop_offset; + } } /* accepted channel configs only seem to be mono/stereo/quad/5.1/7.1, from debug strings */ @@ -640,7 +649,7 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST #endif case EAAC_CODEC_XAS: /* "Xas1": EA-XAS [Dead Space (PC/PS3)] */ - vgmstream->coding_type = coding_EA_XAS; + vgmstream->coding_type = coding_EA_XAS_V1; vgmstream->layout_type = layout_blocked_ea_sns; break; @@ -785,7 +794,7 @@ static size_t get_snr_size(STREAMFILE *streamFile, off_t offset) { static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *streamData, eaac_header *eaac) { segmented_layout_data *data = NULL; STREAMFILE* temp_streamFile[2] = {0}; - off_t offsets[2] = { eaac->stream_offset, eaac->stream_offset + eaac->loop_offset }; + off_t offsets[2] = { eaac->stream_offset, eaac->loop_offset }; int num_samples[2] = { eaac->loop_start, eaac->num_samples - eaac->loop_start}; int segment_count = 2; /* intro/loop */ int i; diff --git a/src/meta/ea_schl.c b/src/meta/ea_schl.c index a5b7cc66..cabefd59 100644 --- a/src/meta/ea_schl.c +++ b/src/meta/ea_schl.c @@ -115,11 +115,11 @@ VGMSTREAM * init_vgmstream_ea_schl(STREAMFILE *streamFile) { /* check extension */ /* they don't seem enforced by EA's tools but usually: - * .asf: ~early [ex. Need for Speed (PC)] + * .asf: ~early (audio stream file?) [ex. Need for Speed (PC)] * .str: ~early [ex. FIFA 2002 (PS1)] * .eam: ~mid (fake?) * .exa: ~mid [ex. 007 - From Russia with Love] - * .sng: ~late (fake?) + * .sng: ~late (FIFA games) * .aud: ~late [ex. FIFA 14 (3DS)] * .strm: MySims Kingdom (Wii) * .stm: FIFA 12 (3DS) diff --git a/src/meta/fag.c b/src/meta/fag.c index 473e77c6..7a38115e 100644 --- a/src/meta/fag.c +++ b/src/meta/fag.c @@ -32,7 +32,7 @@ VGMSTREAM * init_vgmstream_fag(STREAMFILE *streamFile) { if (!vgmstream) goto fail; vgmstream->meta_type = meta_FAG; - vgmstream->sample_rate = 24000; + vgmstream->sample_rate = 22050; vgmstream->num_streams = total_subsongs; vgmstream->stream_size = stream_size; diff --git a/src/meta/genh.c b/src/meta/genh.c index 9daaf61d..e6f3ae3a 100644 --- a/src/meta/genh.c +++ b/src/meta/genh.c @@ -6,33 +6,34 @@ /* known GENH types */ typedef enum { - PSX = 0, /* PSX ADPCM */ - XBOX = 1, /* XBOX IMA ADPCM */ - NGC_DTK = 2, /* NGC ADP/DTK ADPCM */ - PCM16BE = 3, /* 16bit big endian PCM */ - PCM16LE = 4, /* 16bit little endian PCM */ - PCM8 = 5, /* 8bit PCM */ - SDX2 = 6, /* SDX2 (3D0 games) */ - DVI_IMA = 7, /* DVI IMA ADPCM */ - MPEG = 8, /* MPEG (MP3) */ - IMA = 9, /* IMA ADPCM */ - AICA = 10, /* AICA ADPCM (dreamcast) */ - MSADPCM = 11, /* MS ADPCM (windows) */ - NGC_DSP = 12, /* NGC DSP (GC) */ - PCM8_U_int = 13, /* 8bit unsigned PCM (interleaved) */ - PSX_bf = 14, /* PSX ADPCM bad flagged */ - MS_IMA = 15, /* Microsoft IMA ADPCM */ - PCM8_U = 16, /* 8bit unsigned PCM */ - APPLE_IMA4 = 17, /* Apple Quicktime 4-bit IMA ADPCM */ - ATRAC3 = 18, /* raw ATRAC3 */ - ATRAC3PLUS = 19, /* raw ATRAC3PLUS */ - XMA1 = 20, /* raw XMA1 */ - XMA2 = 21, /* raw XMA2 */ - FFMPEG = 22, /* any headered FFmpeg format */ - AC3 = 23, /* AC3/SPDIF */ - PCFX = 24, /* PC-FX ADPCM */ - PCM4 = 25, /* 4bit signed PCM */ - PCM4_U = 26, /* 4bit unsigned PCM */ + PSX = 0, /* PS-ADPCM */ + XBOX = 1, /* XBOX IMA ADPCM */ + NGC_DTK = 2, /* NGC ADP/DTK ADPCM */ + PCM16BE = 3, /* 16-bit big endian PCM */ + PCM16LE = 4, /* 16-bit little endian PCM */ + PCM8 = 5, /* 8-bit PCM */ + SDX2 = 6, /* SDX2 (3D0 games) */ + DVI_IMA = 7, /* DVI IMA ADPCM (high nibble first) */ + MPEG = 8, /* MPEG (MP3) */ + IMA = 9, /* IMA ADPCM (low nibble first) */ + AICA = 10, /* AICA ADPCM (Dreamcast games) */ + MSADPCM = 11, /* MS ADPCM (Windows games) */ + NGC_DSP = 12, /* NGC DSP (Nintendo games) */ + PCM8_U_int = 13, /* 8-bit unsigned PCM (interleaved) */ + PSX_bf = 14, /* PS-ADPCM with bad flags */ + MS_IMA = 15, /* Microsoft IMA ADPCM */ + PCM8_U = 16, /* 8-bit unsigned PCM */ + APPLE_IMA4 = 17, /* Apple Quicktime 4-bit IMA ADPCM */ + ATRAC3 = 18, /* Raw ATRAC3 */ + ATRAC3PLUS = 19, /* Raw ATRAC3PLUS */ + XMA1 = 20, /* Raw XMA1 */ + XMA2 = 21, /* Raw XMA2 */ + FFMPEG = 22, /* Any headered FFmpeg format */ + AC3 = 23, /* AC3/SPDIF */ + PCFX = 24, /* PC-FX ADPCM */ + PCM4 = 25, /* 4-bit signed PCM (3rd and 4th gen games) */ + PCM4_U = 26, /* 4-bit unsigned PCM (3rd and 4th gen games) */ + OKI16 = 27, /* OKI ADPCM with 16-bit output (unlike OKI/VOX/Dialogic ADPCM's 12-bit) */ } genh_type; typedef struct { @@ -118,6 +119,7 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) { case PCFX: coding = coding_PCFX; break; case PCM4: coding = coding_PCM4; break; case PCM4_U: coding = coding_PCM4_U; break; + case OKI16: coding = coding_OKI16; break; default: goto fail; } @@ -204,6 +206,10 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) { vgmstream->codec_config = genh.codec_mode; break; + case coding_OKI16: + vgmstream->layout_type = layout_none; + break; + case coding_MS_IMA: if (!genh.interleave) goto fail; /* creates garbage */ diff --git a/src/meta/gin.c b/src/meta/gin.c new file mode 100644 index 00000000..36953a6e --- /dev/null +++ b/src/meta/gin.c @@ -0,0 +1,53 @@ +#include "meta.h" +#include "../coding/coding.h" + +/* .gin - EA engine sounds [Need for Speed: Most Wanted (multi)] */ +VGMSTREAM * init_vgmstream_gin(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + off_t start_offset; + int loop_flag, channel_count, sample_rate, num_samples; + + + /* checks */ + if (!check_extensions(streamFile, "gin")) + goto fail; + + if (read_32bitBE(0x00,streamFile) != 0x476E7375) /* "Gnsu" */ + goto fail; + + /* contains mapped values for engine RPM sounds but we'll just play the whole thing */ + /* 0x04: size? "20\00\00"? */ + /* 0x08/0c: min/max float RPM? */ + /* 0x10: RPM up? (pitch/frequency) table size */ + /* 0x14: RPM ??? table size */ + /* always LE even on X360/PS3 */ + + num_samples = read_32bitLE(0x18, streamFile); + sample_rate = read_32bitLE(0x1c, streamFile); + start_offset = 0x20 + + (read_32bitLE(0x10, streamFile) + 1) * 0x04 + + (read_32bitLE(0x14, streamFile) + 1) * 0x04; + channel_count = 1; + loop_flag = 0; + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count, loop_flag); + if (!vgmstream) goto fail; + + vgmstream->meta_type = meta_GIN; + vgmstream->sample_rate = sample_rate; + vgmstream->num_samples = num_samples; + + vgmstream->coding_type = coding_EA_XAS_V0; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x13; + + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} diff --git a/src/meta/meta.h b/src/meta/meta.h index 24c9f5fc..9fc7a526 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -472,8 +472,6 @@ VGMSTREAM * init_vgmstream_ps2_msa(STREAMFILE* streamFile); VGMSTREAM * init_vgmstream_ps2_voi(STREAMFILE* streamFile); -VGMSTREAM * init_vgmstream_ps2_khv(STREAMFILE* streamFile); - VGMSTREAM * init_vgmstream_ngc_rkv(STREAMFILE* streamFile); VGMSTREAM * init_vgmstream_p3d(STREAMFILE* streamFile); @@ -511,6 +509,7 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE* streamFile); VGMSTREAM * init_vgmstream_ngc_nst_dsp(STREAMFILE* streamFile); VGMSTREAM * init_vgmstream_baf(STREAMFILE* streamFile); +VGMSTREAM * init_vgmstream_baf_badrip(STREAMFILE* streamFile); VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE* streamFile); @@ -823,4 +822,6 @@ VGMSTREAM * init_vgmstream_imc_container(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_smp(STREAMFILE * streamFile); +VGMSTREAM * init_vgmstream_gin(STREAMFILE * streamFile); + #endif /*_META_H*/ diff --git a/src/meta/ps2_ads.c b/src/meta/ps2_ads.c index b72fb885..fc00f467 100644 --- a/src/meta/ps2_ads.c +++ b/src/meta/ps2_ads.c @@ -174,7 +174,13 @@ VGMSTREAM * init_vgmstream_ps2_ads(STREAMFILE *streamFile) { loop_end_offset = loop_end * 0x10; } #endif - if (loop_end <= body_size / 0x70 && coding_type == coding_PCM16LE) { /* close to body_size */ + if (loop_end <= body_size / 0x200 && coding_type == coding_PCM16LE) { /* close to body_size */ + /* Gofun-go no Sekai: loops is address * 0x200 */ + loop_flag = 1; + loop_start_offset = loop_start * 0x200; + loop_end_offset = loop_end * 0x200; + } + else if (loop_end <= body_size / 0x70 && coding_type == coding_PCM16LE) { /* close to body_size */ /* Armored Core - Nexus: loops is address * 0x70 */ loop_flag = 1; loop_start_offset = loop_start * 0x70; diff --git a/src/meta/ps2_khv.c b/src/meta/ps2_khv.c deleted file mode 100644 index e700025f..00000000 --- a/src/meta/ps2_khv.c +++ /dev/null @@ -1,65 +0,0 @@ -#include "meta.h" -#include "../util.h" - -/* KHV (from Kingdom Hearts 2) */ -/* VAG files with custom headers */ -VGMSTREAM * init_vgmstream_ps2_khv(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - int loop_flag = 0; - int channel_count; - off_t start_offset; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("khv",filename_extension(filename))) goto fail; - - /* check header */ - if (read_32bitBE(0x00,streamFile) != 0x56414770) /* "VAGp" */ - goto fail; - - loop_flag = (read_32bitBE(0x14,streamFile)!=0); - channel_count = 2; - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - start_offset = 0x60; - vgmstream->channels = channel_count; - vgmstream->sample_rate = read_32bitBE(0x10,streamFile); - vgmstream->coding_type = coding_PSX; - vgmstream->num_samples = read_32bitBE(0x0C,streamFile); - if (loop_flag) { - vgmstream->loop_start_sample = read_32bitBE(0x14,streamFile); - vgmstream->loop_end_sample = read_32bitBE(0x18,streamFile); - } - - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = 0x10; - vgmstream->meta_type = meta_PS2_KHV; - - /* open the file for reading */ - { - int i; - STREAMFILE * file; - file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!file) goto fail; - for (i=0;ich[i].streamfile = file; - - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset+ - vgmstream->interleave_block_size*i; - - } - } - - return vgmstream; - - /* clean up anything we may have opened */ -fail: - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} diff --git a/src/meta/txth.c b/src/meta/txth.c index 0a5d8819..375cf021 100644 --- a/src/meta/txth.c +++ b/src/meta/txth.c @@ -6,33 +6,34 @@ /* known TXTH types */ typedef enum { - PSX = 0, /* PSX ADPCM */ - XBOX = 1, /* XBOX IMA ADPCM */ - NGC_DTK = 2, /* NGC ADP/DTK ADPCM */ - PCM16BE = 3, /* 16bit big endian PCM */ - PCM16LE = 4, /* 16bit little endian PCM */ - PCM8 = 5, /* 8bit PCM */ - SDX2 = 6, /* SDX2 (3D0 games) */ - DVI_IMA = 7, /* DVI IMA ADPCM */ - MPEG = 8, /* MPEG (MP3) */ - IMA = 9, /* IMA ADPCM */ - AICA = 10, /* AICA ADPCM (dreamcast) */ - MSADPCM = 11, /* MS ADPCM (windows) */ - NGC_DSP = 12, /* NGC DSP (GC) */ - PCM8_U_int = 13, /* 8bit unsigned PCM (interleaved) */ - PSX_bf = 14, /* PSX ADPCM bad flagged */ - MS_IMA = 15, /* Microsoft IMA ADPCM */ - PCM8_U = 16, /* 8bit unsigned PCM */ - APPLE_IMA4 = 17, /* Apple Quicktime 4-bit IMA ADPCM */ - ATRAC3 = 18, /* raw ATRAC3 */ - ATRAC3PLUS = 19, /* raw ATRAC3PLUS */ - XMA1 = 20, /* raw XMA1 */ - XMA2 = 21, /* raw XMA2 */ - FFMPEG = 22, /* any headered FFmpeg format */ - AC3 = 23, /* AC3/SPDIF */ - PCFX = 24, /* PC-FX ADPCM */ - PCM4 = 25, /* 4bit signed PCM */ - PCM4_U = 26, /* 4bit unsigned PCM */ + PSX = 0, /* PS-ADPCM */ + XBOX = 1, /* XBOX IMA ADPCM */ + NGC_DTK = 2, /* NGC ADP/DTK ADPCM */ + PCM16BE = 3, /* 16-bit big endian PCM */ + PCM16LE = 4, /* 16-bit little endian PCM */ + PCM8 = 5, /* 8-bit PCM */ + SDX2 = 6, /* SDX2 (3D0 games) */ + DVI_IMA = 7, /* DVI IMA ADPCM (high nibble first) */ + MPEG = 8, /* MPEG (MP3) */ + IMA = 9, /* IMA ADPCM (low nibble first) */ + AICA = 10, /* AICA ADPCM (Dreamcast games) */ + MSADPCM = 11, /* MS ADPCM (Windows games) */ + NGC_DSP = 12, /* NGC DSP (Nintendo games) */ + PCM8_U_int = 13, /* 8-bit unsigned PCM (interleaved) */ + PSX_bf = 14, /* PS-ADPCM with bad flags */ + MS_IMA = 15, /* Microsoft IMA ADPCM */ + PCM8_U = 16, /* 8-bit unsigned PCM */ + APPLE_IMA4 = 17, /* Apple Quicktime 4-bit IMA ADPCM */ + ATRAC3 = 18, /* Raw ATRAC3 */ + ATRAC3PLUS = 19, /* Raw ATRAC3PLUS */ + XMA1 = 20, /* Raw XMA1 */ + XMA2 = 21, /* Raw XMA2 */ + FFMPEG = 22, /* Any headered FFmpeg format */ + AC3 = 23, /* AC3/SPDIF */ + PCFX = 24, /* PC-FX ADPCM */ + PCM4 = 25, /* 4-bit signed PCM (3rd and 4th gen games) */ + PCM4_U = 26, /* 4-bit unsigned PCM (3rd and 4th gen games) */ + OKI16 = 27, /* OKI ADPCM with 16-bit output (unlike OKI/VOX/Dialogic ADPCM's 12-bit) */ } txth_type; typedef struct { @@ -180,6 +181,7 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) { case PCFX: coding = coding_PCFX; break; case PCM4: coding = coding_PCM4; break; case PCM4_U: coding = coding_PCM4_U; break; + case OKI16: coding = coding_OKI16; break; default: goto fail; } @@ -280,6 +282,10 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) { vgmstream->codec_config = txth.codec_mode; break; + case coding_OKI16: + vgmstream->layout_type = layout_none; + break; + case coding_MS_IMA: if (!txth.interleave) goto fail; /* creates garbage */ @@ -477,8 +483,10 @@ fail: static STREAMFILE * open_txth(STREAMFILE * streamFile) { + char basename[PATH_LIMIT]; char filename[PATH_LIMIT]; char fileext[PATH_LIMIT]; + const char *subext; STREAMFILE * streamText; /* try "(path/)(name.ext).txth" */ @@ -487,6 +495,22 @@ static STREAMFILE * open_txth(STREAMFILE * streamFile) { streamText = open_streamfile(streamFile,filename); if (streamText) return streamText; + /* try "(path/)(.sub.ext).txth" */ + get_streamfile_basename(streamFile,basename,PATH_LIMIT); + subext = filename_extension(basename); + if (subext != NULL) { + get_streamfile_path(streamFile,filename,PATH_LIMIT); + get_streamfile_ext(streamFile,fileext,PATH_LIMIT); + strcat(filename,"."); + strcat(filename, subext); + strcat(filename,"."); + strcat(filename, fileext); + strcat(filename, ".txth"); + + streamText = open_streamfile(streamFile,filename); + if (streamText) return streamText; + } + /* try "(path/)(.ext).txth" */ get_streamfile_path(streamFile,filename,PATH_LIMIT); get_streamfile_ext(streamFile,fileext,PATH_LIMIT); @@ -596,6 +620,7 @@ static int parse_keyval(STREAMFILE * streamFile_, txth_header * txth, const char else if (0==strcmp(val,"PCFX")) txth->codec = PCFX; else if (0==strcmp(val,"PCM4")) txth->codec = PCM4; else if (0==strcmp(val,"PCM4_U")) txth->codec = PCM4_U; + else if (0==strcmp(val,"OKI16")) txth->codec = OKI16; else goto fail; } else if (0==strcmp(key,"codec_mode")) { @@ -954,7 +979,8 @@ static int get_bytes_to_samples(txth_header * txth, uint32_t bytes) { case AICA: return aica_bytes_to_samples(bytes, txth->channels); case PCFX: - return pcfx_bytes_to_samples(bytes, txth->channels); + case OKI16: + return oki_bytes_to_samples(bytes, txth->channels); /* untested */ case SDX2: diff --git a/src/meta/ubi_bao.c b/src/meta/ubi_bao.c index 75af0e62..dad17883 100644 --- a/src/meta/ubi_bao.c +++ b/src/meta/ubi_bao.c @@ -32,7 +32,7 @@ typedef struct { int subtypes_count[9]; } ubi_bao_header; -static int parse_bao(ubi_bao_header * bao, STREAMFILE *streamFile, off_t offset); +static int parse_bao(ubi_bao_header * bao, STREAMFILE *streamFile, off_t offset, int target_subsong); static int parse_pk_header(ubi_bao_header * bao, STREAMFILE *streamFile); static VGMSTREAM * init_vgmstream_ubi_bao_main(ubi_bao_header * bao, STREAMFILE *streamFile); static STREAMFILE * setup_bao_streamfile(ubi_bao_header *bao, STREAMFILE *streamFile); @@ -265,7 +265,7 @@ static int parse_pk_header(ubi_bao_header * bao, STREAMFILE *streamFile) { size_t index_size, index_header_size; off_t bao_offset, resources_offset; int target_subsong = streamFile->stream_index; - uint8_t *index_buffer = NULL; + STREAMFILE *streamIndex = NULL; STREAMFILE *streamTest = NULL; @@ -274,6 +274,8 @@ static int parse_pk_header(ubi_bao_header * bao, STREAMFILE *streamFile) { goto fail; /* index and resources always LE */ + if (target_subsong == 0) target_subsong = 1; + /* 0x01(3): version, major/minor/release (numbering continues from .sb0/sm0) */ index_size = read_32bitLE(0x04, streamFile); /* can be 0, not including */ resources_offset = read_32bitLE(0x08, streamFile); /* always found even if not used */ @@ -294,21 +296,22 @@ static int parse_pk_header(ubi_bao_header * bao, STREAMFILE *streamFile) { VGM_LOG("BAO: index too big\n"); goto fail; } - index_buffer = malloc(index_size); - read_streamfile(index_buffer, index_header_size, index_size, streamFile); - /* use smaller I/O buffer for performance, as this read lots of small BAO headers all over the place */ + /* use smaller I/O buffers for performance, as this read lots of small headers all over the place */ + streamIndex = reopen_streamfile(streamFile, index_size); + if (!streamIndex) goto fail; + streamTest = reopen_streamfile(streamFile, 0x100); if (!streamTest) goto fail; /* parse index to get target subsong N = Nth audio header BAO */ bao_offset = index_header_size + index_size; for (i = 0; i < index_entries; i++) { - //uint32_t bao_id = get_32bitLE(index_buffer + 0x08*i+ 0x00); - size_t bao_size = get_32bitLE(index_buffer + 0x08*i + 0x04); + //uint32_t bao_id = read_32bitLE(index_header_size + 0x08*i + 0x00, streamIndex); + size_t bao_size = read_32bitLE(index_header_size + 0x08*i + 0x04, streamIndex); /* parse and continue to find out total_subsongs */ - if (!parse_bao(bao, streamTest, bao_offset)) + if (!parse_bao(bao, streamTest, bao_offset, target_subsong)) goto fail; bao_offset += bao_size; /* files simply concat BAOs */ @@ -407,21 +410,20 @@ static int parse_pk_header(ubi_bao_header * bao, STREAMFILE *streamFile) { ;VGM_LOG("BAO stream: id=%x, offset=%x, size=%x, res=%s\n", bao->stream_id, (uint32_t)bao->stream_offset, bao->stream_size, (bao->is_external ? bao->resource_name : "internal")); - free(index_buffer); + close_streamfile(streamIndex); close_streamfile(streamTest); return 1; fail: - free(index_buffer); + close_streamfile(streamIndex); close_streamfile(streamTest); return 0; } /* parse a single BAO (binary audio object) descriptor */ -static int parse_bao(ubi_bao_header * bao, STREAMFILE *streamFile, off_t offset) { +static int parse_bao(ubi_bao_header * bao, STREAMFILE *streamFile, off_t offset, int target_subsong) { int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL; uint32_t bao_version, descriptor_type, descriptor_subtype; size_t header_size; - int target_subsong = streamFile->stream_index; /* 0x00(1): class? usually 0x02 but older BAOs have 0x01 too */ @@ -463,11 +465,11 @@ static int parse_bao(ubi_bao_header * bao, STREAMFILE *streamFile, off_t offset) /* for debugging purposes */ switch(descriptor_subtype) { case 0x00000001: bao->subtypes_count[1]++; break; /* standard */ - case 0x00000002: bao->subtypes_count[2]++; break; /* multilayer??? related to other header BAOs? */ + case 0x00000002: bao->subtypes_count[2]++; break; /* related to localized BAOs? (.lpk) */ case 0x00000003: bao->subtypes_count[3]++; break; /* related to other header BAOs? */ case 0x00000004: bao->subtypes_count[4]++; break; /* related to other header BAOs? */ case 0x00000005: bao->subtypes_count[5]++; break; /* related to other header BAOs? */ - case 0x00000006: bao->subtypes_count[6]++; break; /* some multilayer/table? may contain sounds??? */ + case 0x00000006: bao->subtypes_count[6]++; break; /* multilayer with multiple sounds */ case 0x00000007: bao->subtypes_count[7]++; break; /* related to other header BAOs? */ case 0x00000008: bao->subtypes_count[8]++; break; /* ? (almost empty with some unknown value) */ default: @@ -476,13 +478,26 @@ static int parse_bao(ubi_bao_header * bao, STREAMFILE *streamFile, off_t offset) } //;VGM_ASSERT(descriptor_subtype != 0x01, "UBI BAO: subtype %x at %lx (%lx)\n", descriptor_subtype, offset, offset+header_size+0x04); + if (descriptor_subtype == 0x06) { + ;VGM_LOG("UBI BAO: layer subtype at %lx (%lx)\n", offset, offset+header_size+0x04); + /* todo fix layers + * for scott pilgrim: + * - 0x50: layer count + * - 0x78: layer headers size? + * - 0x7c: prefetch size + * - 0xb4: layer header xN (size 0x30) + * (this header has sample rate, channels, codec, various sizes/num samples) + * - 0x114: good ol' Ubi SB layer header v0x00100009 with classic v0x03 blocked data + * (standard prefetch style, part of data then cut in the middle and links to stream) + */ + goto fail; + } + /* ignore unknown subtypes */ if (descriptor_subtype != 0x00000001) return 1; bao->total_subsongs++; - if (target_subsong == 0) target_subsong = 1; - if (target_subsong != bao->total_subsongs) return 1; diff --git a/src/meta/ubi_sb.c b/src/meta/ubi_sb.c index 14baee78..76d15615 100644 --- a/src/meta/ubi_sb.c +++ b/src/meta/ubi_sb.c @@ -7,7 +7,7 @@ typedef enum { UBI_PC, UBI_PS2, UBI_XBOX, UBI_GC, UBI_X360, UBI_PSP, UBI_PS3, UB typedef struct { ubi_sb_platform platform; int big_endian; - int total_streams; + int total_subsongs; int is_external; ubi_sb_codec codec; @@ -27,7 +27,7 @@ typedef struct { int is_map; uint32_t version; /* 16b+16b major+minor version */ uint32_t version_empty; /* map sbX versions are empty */ - /* folders? events? (often share header_id/type with some descriptors, + /* events? (often share header_id/type with some descriptors, * but may exists without headers or header exist without this) */ size_t section1_num; size_t section1_offset; @@ -58,21 +58,22 @@ typedef struct { size_t section2_entry_size; size_t section3_entry_size; size_t resource_name_size; - off_t cfg_stream_size; - off_t cfg_stream_offset; - off_t cfg_extra_offset; - off_t cfg_group_id; - off_t cfg_stream_type; + /* type 0x01 (sample) config */ + off_t cfga_stream_size; + off_t cfga_stream_offset; + off_t cfga_extra_offset; + off_t cfga_group_id; + off_t cfga_stream_type; - off_t cfg_external_flag; /* stream is external */ - off_t cfg_loop_flag; /* stream loops */ - off_t cfg_num_samples; /* num_samples/loop start */ - off_t cfg_num_samples2; /* num_samples/loop end (if loop set) */ - off_t cfg_sample_rate; - off_t cfg_channels; - off_t cfg_stream_name; /* where the resource name is within the header */ - off_t cfg_extra_name; /* where the resource name is within sectionX */ - off_t cfg_xma_offset; + off_t cfga_external_flag; /* stream is external */ + off_t cfga_loop_flag; /* stream loops */ + off_t cfga_num_samples; /* num_samples/loop start */ + off_t cfga_num_samples2; /* num_samples/loop end (if loop set) */ + off_t cfga_sample_rate; + off_t cfga_channels; + off_t cfga_stream_name; /* where the resource name is within the header */ + off_t cfga_extra_name; /* where the resource name is within sectionX */ + off_t cfga_xma_offset; int and_external_flag; /* value for some flags can be int or bitflags */ int and_loop_flag; int and_group_id; @@ -80,6 +81,12 @@ typedef struct { int has_full_loop; /* loop flag means full loop */ int has_short_channels; /* channels value can be 16b or 32b */ int has_internal_names; /* resource name doubles as internal name in earlier games, or may contain garbage */ + /* type 0x05/0c (sequence?) config */ + off_t cfgs_extra_offset; + off_t cfgs_sequence_count; + /* type 0x06/0d (multilayer) config */ + //off_t cfgl_extra_offset; + /* header/stream info */ uint32_t header_id; /* 16b+16b group+sound id identifier (unique within a sbX, but not smX) */ @@ -87,9 +94,11 @@ typedef struct { size_t stream_size; /* size of the audio data */ off_t stream_offset; /* offset within the data section (internal) or absolute (external) to the audio */ off_t extra_offset; /* offset within sectionX to extra data */ + uint32_t stream_type; /* rough codec value */ uint32_t group_id; /* internal id to reference in section3 */ - uint32_t stream_type; /* rough codec value */ + //int sequence_count; /* number of segments in a sequence type */ + int loop_flag; int loop_start; /* loop starts that aren't 0 do exist but are very rare (ex. Beowulf PSP #33407) */ int num_samples; /* should match manually calculated samples */ @@ -106,7 +115,7 @@ typedef struct { } ubi_sb_header; static VGMSTREAM * init_vgmstream_ubi_sb_main(ubi_sb_header *sb, STREAMFILE *streamFile); -static int parse_sb_header(ubi_sb_header * sb, STREAMFILE *streamFile, int target_stream); +static int parse_sb_header(ubi_sb_header * sb, STREAMFILE *streamFile, int target_subsong); static int config_sb_platform(ubi_sb_header * sb, STREAMFILE *streamFile); static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile); @@ -117,7 +126,7 @@ VGMSTREAM * init_vgmstream_ubi_sb(STREAMFILE *streamFile) { int32_t(*read_32bit)(off_t, STREAMFILE*) = NULL; ubi_sb_header sb = { 0 }; int ok; - int target_stream = streamFile->stream_index; + int target_subsong = streamFile->stream_index; /* check extension (number represents the platform, see later) */ if (!check_extensions(streamFile, "sb0,sb1,sb2,sb3,sb4,sb5,sb6,sb7")) @@ -137,7 +146,7 @@ VGMSTREAM * init_vgmstream_ubi_sb(STREAMFILE *streamFile) { read_32bit = read_32bitLE; } - if (target_stream == 0) target_stream = 1; + if (target_subsong == 0) target_subsong = 1; /* use smaller I/O buffer for performance, as this read lots of small headers all over the place */ streamTest = reopen_streamfile(streamFile, 0x100); @@ -164,7 +173,7 @@ VGMSTREAM * init_vgmstream_ubi_sb(STREAMFILE *streamFile) { sb.section3_offset = sb.sectionX_offset + sb.sectionX_size; sb.sounds_offset = sb.section3_offset + sb.section3_entry_size * sb.section3_num; - if (!parse_sb_header(&sb, streamTest, target_stream)) + if (!parse_sb_header(&sb, streamTest, target_subsong)) goto fail; close_streamfile(streamTest); @@ -184,7 +193,7 @@ VGMSTREAM * init_vgmstream_ubi_sm(STREAMFILE *streamFile) { //int16_t(*read_16bit)(off_t, STREAMFILE*) = NULL; ubi_sb_header sb = { 0 }; int ok, i; - int target_stream = streamFile->stream_index; + int target_subsong = streamFile->stream_index; /* check extension (number represents the platform, see later) */ @@ -205,7 +214,7 @@ VGMSTREAM * init_vgmstream_ubi_sm(STREAMFILE *streamFile) { read_32bit = read_32bitLE; } - if (target_stream == 0) target_stream = 1; + if (target_subsong == 0) target_subsong = 1; /* use smaller I/O buffer for performance, as this read lots of small headers all over the place */ streamTest = reopen_streamfile(streamFile, 0x100); @@ -267,17 +276,16 @@ VGMSTREAM * init_vgmstream_ubi_sm(STREAMFILE *streamFile) { //;VGM_ASSERT(sb.map_unknown != 0, "UBI SM: unknown map_unknown at %x\n", (uint32_t)offset); VGM_ASSERT(sb.version_empty != 0, "UBI SM: unknown version_empty %x\n", (uint32_t)offset); - if (!parse_sb_header(&sb, streamTest, target_stream)) + if (!parse_sb_header(&sb, streamTest, target_subsong)) goto fail; } - if (sb.total_streams == 0) { - VGM_LOG("UBI SB: no streams\n"); + if (sb.total_subsongs == 0) { + VGM_LOG("UBI SB: no subsongs\n"); goto fail; } - if (target_stream < 0 || target_stream > sb.total_streams) { - VGM_LOG("UBI SB: wrong target stream (target=%i, total=%i)\n", target_stream, sb.total_streams); + if (target_subsong < 0 || target_subsong > sb.total_subsongs) { goto fail; } @@ -319,7 +327,7 @@ static VGMSTREAM * init_vgmstream_ubi_sb_main(ubi_sb_header *sb, STREAMFILE *str vgmstream->meta_type = meta_UBI_SB; vgmstream->sample_rate = sb->sample_rate; - vgmstream->num_streams = sb->total_streams; + vgmstream->num_streams = sb->total_subsongs; vgmstream->stream_size = sb->stream_size; vgmstream->num_samples = sb->num_samples; @@ -517,290 +525,165 @@ fail: } -/* debug stuff, for now */ -static void parse_header_type(ubi_sb_header * sb, uint32_t header_type, off_t offset) { +static void build_readable_name(ubi_sb_header * sb, int bank_streams) { + const char *grp_name; + const char *res_name; + uint32_t id; + uint32_t type; + int index; - /* all types may contain memory garbage, making it harder to identify - * usually next types can contain memory from the previous type header, - * so if some non-audio type looks like audio it's probably repeating old data. - * This even happens for common fields (ex. type 06 at 0x08 has prev garbage, not stream size) */ + /* config */ + if (sb->is_map) + grp_name = sb->map_name; + else + grp_name = "bank"; //NULL + id = sb->header_id; + type = sb->header_type; + if (sb->is_map) + index = sb->header_index; //bank_streams; + else + index = sb->header_index; //-1 + res_name = sb->resource_name; - switch(header_type) { - case 0x01: sb->types[0x01]++; break; /* audio (all games) */ - case 0x02: sb->types[0x02]++; break; /* config? (later games) */ - case 0x03: sb->types[0x03]++; break; /* config? (later games) */ - case 0x04: sb->types[0x04]++; break; /* config? (all games) [recheck: SC:CT] */ - case 0x05: sb->types[0x05]++; break; /* config? (all games) [recheck: SC:CT] */ - case 0x06: sb->types[0x06]++; break; /* layer (later games) */ - case 0x07: sb->types[0x07]++; break; /* config? (later games) [recheck: SC:CT] */ - case 0x08: sb->types[0x08]++; break; /* config? (all games) [recheck: SC:CT] */ - //case 0x09: sb->types[0x09]++; break; /* ? */ - case 0x0a: sb->types[0x0a]++; break; /* config? (early games) */ - //case 0x0b: sb->types[0x0b]++; break; /* ? */ - case 0x0c: sb->types[0x0c]++; break; /* config? (early games) */ - case 0x0d: sb->types[0x0d]++; break; /* layer (early games) */ - case 0x0e: sb->types[0x0e]++; break; /* config? (early games) */ - case 0x0f: sb->types[0x0f]++; break; /* config? (early games) */ - default: - VGM_LOG("UBI SB: unknown type %x at %x size %x\n", header_type, (uint32_t)offset, sb->section2_entry_size); - break; //goto fail; + /* create name */ + if (grp_name) { + if ((sb->is_external || sb->has_internal_names) && res_name[0]) { + if (index >= 0) + snprintf(sb->readable_name, sizeof(sb->readable_name), "%s/%04d/%02x-%08x/%s", grp_name, index, type, id, res_name); + else + snprintf(sb->readable_name, sizeof(sb->readable_name), "%s/%02x-%08x/%s", grp_name, type, id, res_name); + } + else { + if (index >= 0) + snprintf(sb->readable_name, sizeof(sb->readable_name), "%s/%04d/%02x-%08x", grp_name, index, type, id); + else + snprintf(sb->readable_name, sizeof(sb->readable_name), "%s/%02x-%08x", grp_name, type, id); + } + } + else { + if ((sb->is_external || sb->has_internal_names) && res_name[0]) { + if (index >= 0) + snprintf(sb->readable_name, sizeof(sb->readable_name), "%04d/%02x-%08x/%s", index, type, id, res_name); + else + snprintf(sb->readable_name, sizeof(sb->readable_name), "%02x-%08x/%s", type, id, res_name); + } else { + if (index >= 0) + snprintf(sb->readable_name, sizeof(sb->readable_name), "%04d/%02x-%08x", index, type, id); + else + snprintf(sb->readable_name, sizeof(sb->readable_name), "%02x-%08x", type, id); + } } - - //;VGM_ASSERT(header_type == 0x06 || header_type == 0x0d, - // "UBI SB: type %x at %x size %x\n", header_type, (uint32_t)offset, sb->section2_entry_size); - - /* layer info for later - * some values may be flags/config as multiple 0x06 can point to the same layer, with different 'flags' */ - - /* headers/layers/blocks also respect endianness (codec is separate, ex. Ubi IMA header is always LE) */ - - /* 0x0d layer [Splinter Cell] */ - /* - type header: - * 0x18: stream offset? - * 0x20: (sample rate * layers) + 1? - * 0x24: layers/channels? - * 0x30: external flag - * 0x34: external name - * 0x5C: stream offset - * 0x64: stream size (not including padding) - * 0x78/7c: codec? - * - * - layer header at stream_offset: - * 0x00: version? (0x00000002) - * 0x04: layers - * 0x08: stream size (not including padding) - * 0x0c: size? - * 0x10: count? - * 0x14: min block size? - * - * - blocked data (unlike other layers, first block data is standard Ubi IMA headers, v3): - * 0x00: block number (from 0x01 to block_count) - * 0x04: current offset (within stream_offset) - * - per layer: - * 0x00: layer data size (varies between blocks, and one layer may have more than other, even the header) - */ - - /* Rainbow Six 3 */ - /* Prince of Persia: Sands of Time (all) 0x000A0004 */ - /* Batman: Rise of Sin Tzu (2003)(GC)-map - 0x000A0002 */ - /* - type header (bizarrely but thankfully doesn't change between platforms): - * 0x1c: sample rate * layers - * 0x20: layers/channels? - * 0x2c: external flag? - * 0x30: external name - * 0x58: stream offset - * 0x5c: original rate * layers? - * 0x60: stream size (not including padding) - * 0x64: number of samples - * - * - layer header at stream_offset (BE on GC): - * 0x00: version? (0x00000004) - * 0x04: layers - * 0x08: stream size (not including padding) - * 0x0c: blocks count - * 0x10: block header size - * 0x14: block size - * 0x18: ? - * 0x1c: size of next section - * - per layer: - * 0x00: layer header size - * codec header per layer - * 0x00~0x20: standard Ubi IMA header (version 0x05, LE) - * - * - blocked data: - * 0x00: block number (from 0x01 to block_count) - * 0x04: current offset (within stream_offset) - * 0x08: always 0x03 - * - per layer: - * 0x00: layer data size (varies between blocks, and one layer may have more than other) - */ - - /* Splinter Cell: Essentials (PSP)-map 0x0012000C */ - /* - type header: - * 0x08: header extra offset - * 0x1c: layers - * 0x28: external flag? - * 0x2c: external flag? - * 0x30: stream name - * 0x5c: sample rate * layers - * 0x60: stream size - * 0x64: stream offset? - * - * - in header extra offset (style 0x10) - * 0x00: sample rate - * 0x04: 16? - * 0x08: channels? - * 0x0c: codec? - * - * - layer header at stream_offset: - * 0x00: version (0x00000007) - * 0x04: config? - * 0x08: layers - * 0x0c: stream size - * 0x10: blocks count - * 0x14: block header size - * 0x18: next block size - * - per layer: - * 0x00: approximate layer data size per block - * - per layer - * 0x00~0x0c: weird header thing? -1/0/0c... - * - * - blocked data: - * 0x00: block number (from 0x01 to block_count) - * 0x04: current offset (within stream_offset) - * 0x08: always 0x03 - * - per layer: - * 0x00: layer data size (varies between blocks, and one layer may have more than other) - */ - - //todo a few XMA streams aren't working (ex. #13072) - /* Splinter Cell: Double Agent (2006)(X360)-map 0x00180006 */ - /* - type header: - * 0x08: header extra offset - * 0x20: layers - * 0x28: external flag? - * 0x30: external flag? - * 0x34: sample rate * layers - * 0x38: stream size - * 0x3c: stream offset - * 0x44: name extra offset - * - * - in header extra offset - * style 0x10 (codec 05 XMA), possible total size 0x34 - * - * - layer header at stream_offset: - * version 0x000C0008 same as 0x000B0008, but codec header size is 0 - * - * - blocked data: - * version same as 0x000B0008 (including mini XMA header + weird tables) - */ - - /* Splinter Cell 3D (2011)(3DS)-map 0x00130001 */ - /* - type header: - * 0x08: header extra offset - * 0x10: layers - * 0x28: stream size - * 0x30: stream offset - * 0x34: name extra offset - * - * - in header extra offset - * style 0x10 (size 0x18?) - * - * - layer header at stream_offset: - * same as 0x00000007 but weird header thing is 0x00~0x08, has header sizes after that - * - * - blocked data: - * same as 0x00000007 - */ - - /* TMNT (2007)(PS2)-bank 0x00190002 */ - /* - type header: - * 0x08: header extra offset - * 0x1c: external flag? - * 0x20: layers - * 0x28: sample rate * layers - * 0x2c: stream size - * 0x30: stream offset - * 0x38: name extra offset - * - * - in header extra offset (style 0x0c) - * 0x00: sample rate - * 0x04: channels - * 0x08: codec - * - * - layer header at stream_offset: - * 0x00: version? (0x000B0008) - * 0x04: config? (0x00/0x0e/0x0b/etc) - * 0x08: layers - * 0x0c: blocks count - * 0x10: block header size - * 0x14: size of header sizes - * 0x18: next block size - * - per layer: - * 0x00: layer header size - * - per layer (if layer header size > 0) - * 0x00~0x20: standard Ubi IMA header (version 0x05), PCM data - * - * - blocked data: - * 0x00: always 0x03 - * 0x04: next block size - * - per layer: - * 0x00: layer data size (varies between blocks, and one layer may have more than other) - */ - - /* Open Season (2005)(PS2)-map 0x00180003 */ - /* Rainbow Six Vegas (2007)(PSP)-bank 0x00180006 */ - /* Star Wars - Lethal Alliance (2006)(PSP)-map 0x00180007 */ - /* - type header: - * 0x0c: header extra offset - * 0x20: layers - * 0x2c: stream size - * 0x30: stream offset - * 0x38: name extra offset - * - * - in header extra offset - * style 0x10 (codec 03=Ubi, 01=PCM16LE in SW:LA/RS:V) - * - layer header at stream_offset: - * - blocked data: - * version 0x000B0008 - */ - - /* TMNT (2007)(PSP)-map 0x00190001 */ - /* - type header: - * 0x0c: header extra offset - * 0x20: layers - * 0x24: total channels? - * 0x28: sample rate * layers? - * 0x2c: stream size - * 0x30: stream offset - * 0x38: name extra offset - * - * - in header extra offset - * style 0x0c - * - layer header at stream_offset: - * - blocked data: - * version 0x000B0008, but codec header size is 0 - */ - - /* TMNT (2007)(GC)-bank 0x00190002 */ - /* Surf's Up (PS3)-bank 0x00190005 */ - /* - type header: - * 0x08: header extra offset - * 0x1c: external flag? - * 0x20: layers - * 0x2c: external flag? (would match header 01) - * 0x30: sample rate * layers - * 0x34: stream size - * 0x38: stream offset - * 0x40: name extra offset - * - * - in header extra offset - * style 0x0c - * - layer header at stream_offset: - * - blocked data: - * version 0x000B0008 - */ - - /* Splinter Cell Classic Trilogy HD (2011)(PS3)-map 0x001d0000 */ - /* - type header: - * 0x0c: header extra offset - * 0x20: layers - * 0x44: stream size - * 0x48: stream offset - * 0x54: name extra offset - * - * - in header extra offset - * style 0x0c - * - layer header at stream_offset: - * - blocked data: - * version 0x000B0008, but codec header size is 0 - */ - } -static int parse_sb_header(ubi_sb_header * sb, STREAMFILE *streamFile, int target_stream) { - int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL; - int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL; +static int parse_header_type_audio(ubi_sb_header * sb, off_t offset, STREAMFILE* streamFile) { + int32_t (*read_32bit)(off_t,STREAMFILE*) = sb->big_endian ? read_32bitBE : read_32bitLE; + int16_t (*read_16bit)(off_t,STREAMFILE*) = sb->big_endian ? read_16bitBE : read_16bitLE; + + /* Single audio header, external or internal. Can be part of a sequence or separate + * (some games don't use sequences at all). */ + + sb->stream_size = read_32bit(offset + sb->cfga_stream_size, streamFile); + sb->extra_offset = read_32bit(offset + sb->cfga_extra_offset, streamFile) + sb->sectionX_offset; + sb->stream_offset = read_32bit(offset + sb->cfga_stream_offset, streamFile); + sb->channels = (sb->has_short_channels) ? + (uint16_t)read_16bit(offset + sb->cfga_channels, streamFile) : + (uint32_t)read_32bit(offset + sb->cfga_channels, streamFile); + sb->sample_rate = read_32bit(offset + sb->cfga_sample_rate, streamFile); + sb->stream_type = read_32bit(offset + sb->cfga_stream_type, streamFile); + + if (sb->cfga_loop_flag) { + sb->loop_flag = (read_32bit(offset + sb->cfga_loop_flag, streamFile) & sb->and_loop_flag); + } + + if (sb->loop_flag) { + sb->loop_start = read_32bit(offset + sb->cfga_num_samples, streamFile); + sb->num_samples = read_32bit(offset + sb->cfga_num_samples2, streamFile) + sb->loop_start; + if (sb->has_full_loop) { /* early games just repeat and don't set loop start */ + sb->num_samples = sb->loop_start; + sb->loop_start = 0; + } + /* loop starts that aren't 0 do exist but are very rare (ex. Beowulf PSP #33407) + * also rare are looping external streams (ex. Surf's Up PSP #1462) */ + } else { + sb->num_samples = read_32bit(offset + sb->cfga_num_samples, streamFile); + } + + if (sb->cfga_group_id) { + sb->group_id = read_32bit(offset + sb->cfga_group_id, streamFile); + if (sb->and_group_id) sb->group_id &= sb->and_group_id; + if (sb->shr_group_id) sb->group_id >>= sb->shr_group_id; + } + + if (sb->cfga_external_flag) { + sb->is_external = (read_32bit(offset + sb->cfga_external_flag, streamFile) & sb->and_external_flag); + } + + /* external stream name can be found in the header (first versions) or the sectionX table (later versions) */ + if (sb->cfga_stream_name) { + read_string(sb->resource_name, sb->resource_name_size, offset + sb->cfga_stream_name, streamFile); + } else { + sb->cfga_stream_name = read_32bit(offset + sb->cfga_extra_name, streamFile); + if (sb->cfga_stream_name != 0xFFFFFFFF) + read_string(sb->resource_name, sb->resource_name_size, sb->sectionX_offset + sb->cfga_stream_name, streamFile); + } + + return 1; +//fail: +// return 0; +} + +static int parse_header_type_sequence(ubi_sb_header * sb, off_t offset, STREAMFILE* streamFile) { +// int32_t (*read_32bit)(off_t,STREAMFILE*) = sb->big_endian ? read_32bitBE : read_32bitLE; + + /* A "sequence" that includes N audio segments, defined as a chain of section2 entries. + * + * They don't include lead-in/outs and look loopable. Several sequences can reuse + * audio segments (variations of the same songs), or can be single entries (pointing + * to a full song or a lead-out). + * + * Sequences seem to include only music or dialogues, so even single entries may be useful to parse. */ + + /* - rough format: */ + /* extra table offset (references id?) at ~0x0c */ + /* flags? */ + /* id? possibly related to sequence lead-out? */ + /* id? possibly related to sequence lead-in? */ + /* sequence count at ~0x28/2c */ + + /* - in the extra table, per sequence count: + * 0x00: section2 entry number (points to audio types) + * 0x04+ size varies (0x10-0x14 are common) + * at the end: some kind of ID? + */ + +#if 0 + if (!sb->cfgs_sequence_count) { + VGM_LOG("UBI SB: segment found but not configured at %lx\n", offset); + goto fail; + } + + return 1; +fail: +#endif + return 0; +} + +static int parse_header_type_layer(ubi_sb_header * sb, off_t offset, STREAMFILE* streamFile) { +// int32_t (*read_32bit)(off_t,STREAMFILE*) = sb->big_endian ? read_32bitBE : read_32bitLE; +// int16_t (*read_16bit)(off_t,STREAMFILE*) = sb->big_endian ? read_16bitBE : read_16bitLE; + +// goto fail; + + /* some values may be flags/config as multiple 0x06 can point to the same layer, with different 'flags'? */ + + return 1; +//fail: +// return 0; +} + + +static int parse_sb_header(ubi_sb_header * sb, STREAMFILE *streamFile, int target_subsong) { + int32_t (*read_32bit)(off_t,STREAMFILE*) = sb->big_endian ? read_32bitBE : read_32bitLE; int i, j, k, bank_streams = 0, prev_streams; @@ -808,124 +691,137 @@ static int parse_sb_header(ubi_sb_header * sb, STREAMFILE *streamFile, int targe sb->section1_offset,sb->section1_entry_size,sb->section1_num,sb->section2_offset,sb->section2_entry_size,sb->section2_num, sb->section3_offset,sb->section3_entry_size,sb->section3_num,sb->sectionX_offset,sb->sectionX_size); - - if (sb->big_endian) { - read_32bit = read_32bitBE; - read_16bit = read_16bitBE; - } else { - read_32bit = read_32bitLE; - read_16bit = read_16bitLE; - } - - prev_streams = sb->total_streams; + prev_streams = sb->total_subsongs; /* find target stream info in section2 */ for (i = 0; i < sb->section2_num; i++) { off_t offset = sb->section2_offset + sb->section2_entry_size*i; - uint32_t header_type; + uint32_t header_id, header_type; + /* parse base header (possibly called "resource" or "object") */ + header_id = read_32bit(offset + 0x00, streamFile); header_type = read_32bit(offset + 0x04, streamFile); - parse_header_type(sb, header_type, offset); + + if (header_type <= 0x00 || header_type >= 0x10 || header_type == 0x09 || header_type == 0x0b) { + VGM_LOG("UBI SB: unknown type %x at %x size %x\n", header_type, (uint32_t)offset, sb->section2_entry_size); + goto fail; + } + + //;VGM_ASSERT(header_type == 0x06 || header_type == 0x0d, + // "UBI SB: type %x at %x size %x\n", header_type, (uint32_t)offset, sb->section2_entry_size); + + sb->types[header_type]++; /* ignore non-audio entries */ if (header_type != 0x01) continue; /* update streams (total_stream also doubles as current) */ - sb->total_streams++; bank_streams++; - if (sb->total_streams != target_stream) + sb->total_subsongs++; + if (sb->total_subsongs != target_subsong) continue; - - /* parse audio entry based on config */ + /* parse target entry */ sb->header_index = i; sb->header_offset = offset; - sb->header_id = read_32bit(offset + 0x00, streamFile); - sb->header_type = read_32bit(offset + 0x04, streamFile); - sb->stream_size = read_32bit(offset + sb->cfg_stream_size, streamFile); - sb->extra_offset = read_32bit(offset + sb->cfg_extra_offset, streamFile) + sb->sectionX_offset; - sb->stream_offset = read_32bit(offset + sb->cfg_stream_offset, streamFile); - sb->channels = (sb->has_short_channels) ? - (uint16_t)read_16bit(offset + sb->cfg_channels, streamFile) : - (uint32_t)read_32bit(offset + sb->cfg_channels, streamFile); - sb->sample_rate = read_32bit(offset + sb->cfg_sample_rate, streamFile); - sb->stream_type = read_32bit(offset + sb->cfg_stream_type, streamFile); + sb->header_id = header_id; + sb->header_type = header_type; - if (sb->cfg_loop_flag) { - sb->loop_flag = (read_32bit(offset + sb->cfg_loop_flag, streamFile) & sb->and_loop_flag); + switch(header_type) { + case 0x01: /* old and new */ + if (!parse_header_type_audio(sb, offset, streamFile)) + goto fail; + break; + case 0x02: + /* A group, possibly to play with config. (ex: 0x08 (float 0.3) + 0x01) */ + goto fail; + case 0x03: + //case 0x09? + /* A group, other way to play things? (ex: 0x03 + 0x04) */ + goto fail; + case 0x04: /* newer/older */ + case 0x0a: /* older */ + /* A group of N audio/sequences, seemingly 'random' type to play one in the group + * (usually includes voice/sfx like death screams, but may include sequences). + * Header is similar to sequences (count in header, points to extra table's N entries in section2) */ + goto fail; + case 0x05: /* newer */ + case 0x0c: /* older */ + if (!parse_header_type_sequence(sb, offset, streamFile)) + goto fail; + break; + case 0x06: /* newer */ + case 0x0d: /* older */ + if (!parse_header_type_layer(sb, offset, streamFile)) + goto fail; + break; + case 0x07: + //case 0x0e? + /* Another group of something (single entry?), rare. */ + goto fail; + case 0x08: /* newer (also in older with 0x0f) */ + case 0x0f: /* older */ + /* Audio config? (almost all fields 0 except sometimes 1.0 float in the middle). + * In older games may also point to the extra table and look different, maybe equivalent to another type. */ + goto fail; + + default: + /* debug strings reference: + * - TYPE_SAMPLE: should be 0x01 (also "sound resource") + * - TYPE_MULTITRACK: should be 0x06/0x0d (also "multilayer resource") + * - TYPE_SILENCE: ? + * sequences may be "theme resource" + * + * possible type names from .bnm (.sb's predecessor): + * 0: TYPE_INVALID + * 1: TYPE_SAMPLE + * 2: TYPE_MIDI + * 3: TYPE_CDAUDIO + * 4: TYPE_SEQUENCE + * 5: TYPE_SWITCH_OLD + * 6: TYPE_SPLIT + * 7: TYPE_THEME_OLD + * 8: TYPE_SWITCH + * 9: TYPE_THEME_OLD2 + * A: TYPE_RANDOM + * B: TYPE_THEME0 + */ + + /* All types may contain memory garbage, making it harder to identify fields (platforms + * and games are affected differently by this). Often types contain memory from the previous + * type header unless overwritten, random memory, or default initialization garbage. + * So if some non-audio type looks like audio it's probably repeating old data. + * This even happens for common fields (ex. type 06 at 0x08 has prev garbage, not stream size). */ + goto fail; } - if (sb->loop_flag) { - sb->loop_start = read_32bit(offset + sb->cfg_num_samples, streamFile); - sb->num_samples = read_32bit(offset + sb->cfg_num_samples2, streamFile) + sb->loop_start; - if (sb->has_full_loop) { /* early games just repeat and don't set loop start */ - sb->num_samples = sb->loop_start; - sb->loop_start = 0; - } - /* loop starts that aren't 0 do exist but are very rare (ex. Beowulf PSP #33407) - * also rare are looping external streams (ex. Surf's Up PSP #1462) */ - } else { - sb->num_samples = read_32bit(offset + sb->cfg_num_samples, streamFile); - } - if (sb->cfg_group_id) { - sb->group_id = read_32bit(offset + sb->cfg_group_id, streamFile); - if (sb->and_group_id) sb->group_id &= sb->and_group_id; - if (sb->shr_group_id) sb->group_id >>= sb->shr_group_id; - } - - if (sb->cfg_external_flag) { - sb->is_external = (read_32bit(offset + sb->cfg_external_flag, streamFile) & sb->and_external_flag); - } - - /* external stream name can be found in the header (first versions) or the sectionX table (later versions) */ - if (sb->cfg_stream_name) { - read_string(sb->resource_name, sb->resource_name_size, offset + sb->cfg_stream_name, streamFile); - } else { - sb->cfg_stream_name = read_32bit(offset + sb->cfg_extra_name, streamFile); - if (sb->cfg_stream_name != 0xFFFFFFFF) - read_string(sb->resource_name, sb->resource_name_size, sb->sectionX_offset + sb->cfg_stream_name, streamFile); - } - - /* build a usable name */ - if (sb->is_map) { - if ((sb->is_external || sb->has_internal_names) && sb->resource_name[0]) { - snprintf(sb->readable_name, sizeof(sb->readable_name), "%s/%d/%08x/%s", sb->map_name, bank_streams, sb->header_id, sb->resource_name); - } else { - snprintf(sb->readable_name, sizeof(sb->readable_name), "%s/%d/%08x", sb->map_name, bank_streams, sb->header_id); - } - } else { - if ((sb->is_external || sb->has_internal_names) && sb->resource_name[0]) { - snprintf(sb->readable_name, sizeof(sb->readable_name), "%08x/%s", sb->header_id, sb->resource_name); - } else { - snprintf(sb->readable_name, sizeof(sb->readable_name), "%08x", sb->header_id); - } - } + /* maps can contain +10000 subsongs, we need something helpful */ + build_readable_name(sb, bank_streams); } - //;VGM_LOG("UBI SB: types "); for (int i = 0; i < 16; i++) { VGM_ASSERT(sb->types[i], "%02x=%i ",i,sb->types[i]); } VGM_LOG("\n"); + ;VGM_LOG("UBI SB: types "); for (int i = 0; i < 16; i++) { VGM_ASSERT(sb->types[i], "%02x=%i ",i,sb->types[i]); } VGM_LOG("\n"); if (sb->is_map) { - if (bank_streams == 0 || target_stream <= prev_streams || target_stream > sb->total_streams) + if (bank_streams == 0 || target_subsong <= prev_streams || target_subsong > sb->total_subsongs) return 1; /* Target stream is not in this map */ } else { - if (sb->total_streams == 0) { - VGM_LOG("UBI SB: no streams\n"); + if (sb->total_subsongs == 0) { + VGM_LOG("UBI SB: no subsongs\n"); goto fail; } - if (target_stream < 0 || target_stream > sb->total_streams) { - VGM_LOG("UBI SB: wrong target stream (target=%i, total=%i)\n", target_stream, sb->total_streams); + if (target_subsong < 0 || target_subsong > sb->total_subsongs) { goto fail; } VGM_ASSERT(sb->section3_num > 2, "UBI SB: section3 > 2 found\n"); } - if (!(sb->cfg_group_id || sb->is_map) && sb->section3_num > 1) { + if (!(sb->cfga_group_id || sb->is_map) && sb->section3_num > 1) { VGM_LOG("UBI SB: unexpected number of internal stream groups %i\n", sb->section3_num); goto fail; } @@ -1042,9 +938,10 @@ static int parse_sb_header(ubi_sb_header * sb, STREAMFILE *streamFile, int targe sb->codec = RAW_AT3; break; - case 0x08: /* Ubi IMA v2 (early games) or ATRAC3 */ + case 0x08: /* Ubi IMA v2/v3 (early games) or ATRAC3 */ switch (sb->version) { case 0x00000003: /* Donald Duck: Goin' Quackers */ + case 0x00000004: /* Myst III: Exile */ sb->codec = UBI_ADPCM; break; default: @@ -1060,7 +957,7 @@ static int parse_sb_header(ubi_sb_header * sb, STREAMFILE *streamFile, int targe if (sb->codec == RAW_XMA1) { /* this field is only seen in X360 games, points at XMA1 header in extra section */ - sb->xma_header_offset = read_32bit(sb->header_offset + sb->cfg_xma_offset, streamFile) + sb->sectionX_offset; + sb->xma_header_offset = read_32bit(sb->header_offset + sb->cfga_xma_offset, streamFile) + sb->sectionX_offset; } @@ -1084,7 +981,7 @@ static int parse_sb_header(ubi_sb_header * sb, STREAMFILE *streamFile, int targe int index = read_32bit(table_offset + 0x08 * j + 0x00, streamFile) & 0x0000FFFF; if (index == sb->header_index) { - if (!sb->cfg_group_id && table2_num > 1) { + if (!sb->cfga_group_id && table2_num > 1) { VGM_LOG("UBI SB: unexpected number of internal stream map groups %i at %x\n", table2_num, (uint32_t)table2_offset); goto fail; } @@ -1114,7 +1011,7 @@ static int parse_sb_header(ubi_sb_header * sb, STREAMFILE *streamFile, int targe /* banks store internal sounds offsets in table: group id + group size, find the matching entry */ - if (sb->cfg_group_id && sb->section3_num > 1) { + if (sb->cfga_group_id && sb->section3_num > 1) { for (i = 0; i < sb->section3_num; i++) { off_t offset = sb->section3_offset + sb->section3_entry_size * i; @@ -1201,6 +1098,23 @@ fail: return 0; } +#if 0 +static int config_sb_version_layer2(ubi_sb_header * sb) { + + sb->cfgc_sequence_count = 0x28; //POP + sb->cfg5_sequence_count = 0x28; //POP WW + sb->cfg5_sequence_count = 0x2c; //POP TT, TMNT + + sb->cfgd_layer_rate = 0x1c; + sb->cfgd_layer_count = 0x20; + /* 0x2c: external flag? */ + sb->cfgd_stream_name = 0x30; + sb->cfgd_stream_offset = 0x58; + /* 0x5c: original layer rate? */ + sb->cfgd_stream_size = 0x60; + sb->cfgd_num_samples = 0x64; +} +#endif static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) { int is_biadd_psp = 0; @@ -1232,14 +1146,14 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) { sb->section3_entry_size = 0x08; sb->resource_name_size = 0x24; /* maybe 0x28 or 0x20 for some but ok enough (null terminated) */ /* this is same in all games since ~2003 */ - sb->cfg_stream_size = 0x08; - sb->cfg_extra_offset = 0x0c; - sb->cfg_stream_offset = 0x10; + sb->cfga_stream_size = 0x08; + sb->cfga_extra_offset = 0x0c; + sb->cfga_stream_offset = 0x10; + sb->cfgs_extra_offset = 0x0c; sb->and_external_flag = 0x01; sb->and_loop_flag = 0x01; - //todo: create generic configs to simplify parsing, since many share header but change entry sizes /* Batman: Vengeance (2001)(PS2)-map 0x00000003 */ /* Tom Clancy's Rainbow Six - Vegas 2 (2008)(PC)-? */ @@ -1258,25 +1172,92 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) { sb->map_version = 1; - sb->cfg_stream_size = 0x0c; - sb->cfg_extra_offset = 0x10; - sb->cfg_stream_offset = 0x14; + sb->cfga_stream_size = 0x0c; + sb->cfga_extra_offset = 0x10; + sb->cfga_stream_offset = 0x14; - sb->cfg_group_id = 0x2c; - sb->cfg_external_flag = 0x30; - sb->cfg_loop_flag = 0x34; - sb->cfg_num_samples = 0x48; - sb->cfg_num_samples2 = 0x48; /* full loop */ - sb->cfg_sample_rate = 0x50; - sb->cfg_channels = 0x56; - sb->cfg_stream_type = 0x58; - sb->cfg_stream_name = 0x5c; + sb->cfga_group_id = 0x2c; + sb->cfga_external_flag = 0x30; + sb->cfga_loop_flag = 0x34; + sb->cfga_num_samples = 0x48; + sb->cfga_num_samples2 = 0x48; /* full loop */ + sb->cfga_sample_rate = 0x50; + sb->cfga_channels = 0x56; + sb->cfga_stream_type = 0x58; + sb->cfga_stream_name = 0x5c; sb->has_short_channels = 1; sb->has_full_loop = 1; + + sb->cfgs_extra_offset = 0x10; + sb->cfgs_sequence_count = 0x2c; //has layer 0d return 1; } +#if 0 + /* Batman: Vengeance (2001)(PS2)-map */ + if (sb->version == 0x00000003 && sb->platform == UBI_PS2) { + sb->section1_entry_size = 0x30; + sb->section2_entry_size = 0x3c; + + sb->map_version = 1; + + sb->cfga_stream_size = 0x0c; + sb->cfga_extra_offset = 0x10; + sb->cfga_stream_offset = 0x14; + + sb->cfga_group_id = 0x1c?; + sb->cfga_external_flag = 0x1c?; + sb->cfga_loop_flag = 0x1c?; + sb->cfga_num_samples = 0x20? 28? 2c? + sb->cfga_num_samples2 = 0x20? 28? 2c? + sb->cfga_sample_rate = 0x24; + sb->cfga_channels = 0x2a? + sb->cfga_stream_type = 0x34; + sb->cfga_stream_name = -1; //has implicit stream name + + sb->has_short_channels = 1; + sb->has_full_loop = 1; + + //has layer 0d + return 1; + } +#endif + +#if 0 + //todo offsets seems to work differently (stream offset is always 0) + /* Myst III: Exile (2001)(PS2)-map */ + if (sb->version == 0x00000004 && sb->platform == UBI_PS2) { + sb->section1_entry_size = 0x34; + sb->section2_entry_size = 0x70; + + sb->map_version = 1; + + sb->cfga_stream_size = 0x0c; + sb->cfga_extra_offset = 0x10; + sb->cfga_stream_offset = 0x14; + + sb->cfga_group_id = 0x1c; + sb->cfga_external_flag = 0x1c; + sb->cfga_loop_flag = 0x1c; + sb->cfga_channels = 0x24; + sb->cfga_sample_rate = 0x28; + sb->cfga_num_samples = 0x2c; + sb->cfga_num_samples2 = 0x34; + sb->cfga_stream_name = 0x44; + sb->cfga_stream_type = 0x6c; + + sb->and_external_flag = 0x04; + sb->and_loop_flag = 0x10; + sb->and_group_id = 0x08; + sb->shr_group_id = 3; + + sb->cfgs_extra_offset = 0x10; + sb->cfgs_sequence_count = 0x2c; + return 1; + } +#endif + #if 0 /* Splinter Cell (2002)(PC)-map */ @@ -1292,19 +1273,19 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) { sb->map_version = 1; - sb->cfg_stream_size = 0x0c; - sb->cfg_extra_offset = 0x10; - sb->cfg_stream_offset = 0x14; + sb->cfga_stream_size = 0x0c; + sb->cfga_extra_offset = 0x10; + sb->cfga_stream_offset = 0x14; - //sb->cfg_loop_flag = 0x24; //? - sb->cfg_external_flag = 0x28; - sb->cfg_group_id = 0x2c; - sb->cfg_num_samples = 0x30; - //sb->cfg_num_samples2 = 0x38; - sb->cfg_sample_rate = 0x44; - sb->cfg_channels = 0x4a; - sb->cfg_stream_type = 0x4c; - sb->cfg_stream_name = 0x50; + //sb->cfga_loop_flag = 0x24; //? + sb->cfga_external_flag = 0x28; + sb->cfga_group_id = 0x2c; + sb->cfga_num_samples = 0x30; + //sb->cfga_num_samples2 = 0x38; + sb->cfga_sample_rate = 0x44; + sb->cfga_channels = 0x4a; + sb->cfga_stream_type = 0x4c; + sb->cfga_stream_name = 0x50; sb->has_short_channels = 1; sb->has_internal_names = 1; @@ -1314,6 +1295,7 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) { #endif #if 0 /* Splinter Cell (2002)(Xbox)-map */ + /* Splinter Cell: Pandora Tomorrow (2004)(Xbox)-map */ if (sb->version == 0x00000007 && sb->platform == UBI_XBOX) { /* Stream types: * 0x01: PCM @@ -1325,19 +1307,19 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) { sb->map_version = 1; - sb->cfg_stream_size = 0x0c; - sb->cfg_extra_offset = 0x10; - sb->cfg_stream_offset = 0x14; + sb->cfga_stream_size = 0x0c; + sb->cfga_extra_offset = 0x10; + sb->cfga_stream_offset = 0x14; - sb->cfg_group_id = 0x24? 0x2c; - sb->cfg_external_flag = 0x28; - sb->cfg_loop_flag = 0x2c? 0x24? - sb->cfg_num_samples = 0x30; - sb->cfg_num_samples2 = 0x38; - sb->cfg_sample_rate = 0x44; - sb->cfg_channels = 0x4a; - sb->cfg_stream_type = 0x4c; - sb->cfg_stream_name = 0x50; + sb->cfga_group_id = 0x24? 0x2c; + sb->cfga_external_flag = 0x28; + sb->cfga_loop_flag = 0x2c? 0x24? + sb->cfga_num_samples = 0x30; + sb->cfga_num_samples2 = 0x38; + sb->cfga_sample_rate = 0x44; + sb->cfga_channels = 0x4a; + sb->cfga_stream_type = 0x4c; + sb->cfga_stream_name = 0x50; sb->has_short_channels = 1; sb->has_internal_names = 1; @@ -1351,18 +1333,20 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) { sb->section1_entry_size = 0x64; sb->section2_entry_size = 0x80; - sb->cfg_external_flag = 0x24; - sb->cfg_loop_flag = 0x28; - sb->cfg_group_id = 0x2c; - sb->cfg_num_samples = 0x30; - sb->cfg_num_samples2 = 0x38; - sb->cfg_sample_rate = 0x44; - sb->cfg_channels = 0x4a; - sb->cfg_stream_type = 0x4c; - sb->cfg_stream_name = 0x50; + sb->cfga_external_flag = 0x24; + sb->cfga_loop_flag = 0x28; + sb->cfga_group_id = 0x2c; + sb->cfga_num_samples = 0x30; + sb->cfga_num_samples2 = 0x38; + sb->cfga_sample_rate = 0x44; + sb->cfga_channels = 0x4a; + sb->cfga_stream_type = 0x4c; + sb->cfga_stream_name = 0x50; sb->has_short_channels = 1; sb->has_internal_names = 1; + + sb->cfgs_sequence_count = 0x28; //has layer 0d (main game) return 1; } @@ -1373,20 +1357,22 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) { sb->section1_entry_size = 0x48; sb->section2_entry_size = 0x6c; - sb->cfg_external_flag = 0x18; - sb->cfg_loop_flag = 0x18; - sb->cfg_group_id = 0x18; - sb->cfg_channels = 0x20; - sb->cfg_sample_rate = 0x24; - sb->cfg_num_samples = 0x30; /* may be null */ - sb->cfg_num_samples2 = 0x38; /* may be null */ - sb->cfg_stream_name = 0x40; - sb->cfg_stream_type = 0x68; + sb->cfga_external_flag = 0x18; + sb->cfga_loop_flag = 0x18; + sb->cfga_group_id = 0x18; + sb->cfga_channels = 0x20; + sb->cfga_sample_rate = 0x24; + sb->cfga_num_samples = 0x30; /* may be null */ + sb->cfga_num_samples2 = 0x38; /* may be null */ + sb->cfga_stream_name = 0x40; + sb->cfga_stream_type = 0x68; sb->and_external_flag = 0x04; sb->and_loop_flag = 0x10; sb->and_group_id = 0x08; sb->shr_group_id = 3; + + sb->cfgs_sequence_count = 0x28; //has layer 0d (main game) return 1; } @@ -1397,18 +1383,20 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) { sb->section1_entry_size = 0x64; sb->section2_entry_size = 0x78; - sb->cfg_external_flag = 0x24; - sb->cfg_group_id = 0x28; - sb->cfg_loop_flag = 0x2c; - sb->cfg_num_samples = 0x30; - sb->cfg_num_samples2 = 0x38; - sb->cfg_sample_rate = 0x44; - sb->cfg_channels = 0x4a; - sb->cfg_stream_type = 0x4c; /* may contain garbage */ - sb->cfg_stream_name = 0x50; + sb->cfga_external_flag = 0x24; + sb->cfga_group_id = 0x28; + sb->cfga_loop_flag = 0x2c; + sb->cfga_num_samples = 0x30; + sb->cfga_num_samples2 = 0x38; + sb->cfga_sample_rate = 0x44; + sb->cfga_channels = 0x4a; + sb->cfga_stream_type = 0x4c; /* may contain garbage */ + sb->cfga_stream_name = 0x50; sb->has_short_channels = 1; sb->has_internal_names = 1; + + sb->cfgs_sequence_count = 0x28; //has layer 0d (main game) return 1; } @@ -1423,18 +1411,20 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) { sb->map_version = 2; - sb->cfg_external_flag = 0x20; - sb->cfg_group_id = 0x24; - sb->cfg_loop_flag = 0x28; - sb->cfg_num_samples = 0x2c; - sb->cfg_num_samples2 = 0x34; - sb->cfg_sample_rate = 0x40; - sb->cfg_channels = 0x46; - sb->cfg_stream_type = 0x48; - sb->cfg_stream_name = 0x4c; + sb->cfga_external_flag = 0x20; + sb->cfga_group_id = 0x24; + sb->cfga_loop_flag = 0x28; + sb->cfga_num_samples = 0x2c; + sb->cfga_num_samples2 = 0x34; + sb->cfga_sample_rate = 0x40; + sb->cfga_channels = 0x46; + sb->cfga_stream_type = 0x48; + sb->cfga_stream_name = 0x4c; sb->has_short_channels = 1; //has layer 0d (POP:SOT main game, Batman) + + sb->cfgs_sequence_count = 0x28; return 1; } @@ -1443,38 +1433,39 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) { sb->section1_entry_size = 0x48; sb->section2_entry_size = 0x6c; - sb->cfg_external_flag = 0x18; - sb->cfg_loop_flag = 0x18; - sb->cfg_group_id = 0x18; - sb->cfg_channels = 0x20; - sb->cfg_sample_rate = 0x24; - sb->cfg_num_samples = 0x30; /* may be null */ - sb->cfg_num_samples2 = 0x38; /* may be null */ - sb->cfg_stream_name = 0x40; - sb->cfg_stream_type = 0x68; + sb->cfga_external_flag = 0x18; + sb->cfga_loop_flag = 0x18; + sb->cfga_group_id = 0x18; + sb->cfga_channels = 0x20; + sb->cfga_sample_rate = 0x24; + sb->cfga_num_samples = 0x30; /* may be null */ + sb->cfga_num_samples2 = 0x38; /* may be null */ + sb->cfga_stream_name = 0x40; + sb->cfga_stream_type = 0x68; sb->and_external_flag = 0x04; sb->and_loop_flag = 0x10; sb->and_group_id = 0x08; sb->shr_group_id = 3; + //has layer 0d return 1; } - /* Splincer Cell: Pandora Tomorrow (2006)(PS2)-bank (?) */ + /* Splincer Cell: Pandora Tomorrow(?) (2006)(PS2)-bank */ if (sb->version == 0x000A0008 && sb->platform == UBI_PS2) { sb->section1_entry_size = 0x48; sb->section2_entry_size = 0x6c; - sb->cfg_external_flag = 0x18; - sb->cfg_loop_flag = 0x18; - sb->cfg_group_id = 0x18; - sb->cfg_channels = 0x20; - sb->cfg_sample_rate = 0x24; - sb->cfg_num_samples = 0x30; /* may be null */ - sb->cfg_num_samples2 = 0x38; /* may be null */ - sb->cfg_stream_name = 0x40; - sb->cfg_stream_type = 0x68; + sb->cfga_external_flag = 0x18; + sb->cfga_loop_flag = 0x18; + sb->cfga_group_id = 0x18; + sb->cfga_channels = 0x20; + sb->cfga_sample_rate = 0x24; + sb->cfga_num_samples = 0x30; /* may be null */ + sb->cfga_num_samples2 = 0x38; /* may be null */ + sb->cfga_stream_name = 0x40; + sb->cfga_stream_type = 0x68; sb->and_external_flag = 0x04; sb->and_loop_flag = 0x10; @@ -1485,19 +1476,19 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) { } /* Myst IV Demo (2004)(PC)-bank */ - if (sb->version == 0x00100000 && sb->platform == UBI_PC) { /* final game is different */ + if (sb->version == 0x00100000 && sb->platform == UBI_PC) { sb->section1_entry_size = 0x68; sb->section2_entry_size = 0xa4; - sb->cfg_external_flag = 0x24; - sb->cfg_loop_flag = 0x28; - sb->cfg_group_id = 0x2c; - sb->cfg_num_samples = 0x30; - sb->cfg_num_samples2 = 0x38; - sb->cfg_sample_rate = 0x44; - sb->cfg_channels = 0x4c; - sb->cfg_stream_type = 0x50; - sb->cfg_stream_name = 0x54; + sb->cfga_external_flag = 0x24; + sb->cfga_loop_flag = 0x28; + sb->cfga_group_id = 0x2c; + sb->cfga_num_samples = 0x30; + sb->cfga_num_samples2 = 0x38; + sb->cfga_sample_rate = 0x44; + sb->cfga_channels = 0x4c; + sb->cfga_stream_type = 0x50; + sb->cfga_stream_name = 0x54; sb->has_internal_names = 1; return 1; @@ -1508,17 +1499,19 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) { sb->section1_entry_size = 0x6c; sb->section2_entry_size = 0x84; - sb->cfg_external_flag = 0x24; - sb->cfg_loop_flag = 0x28; - sb->cfg_group_id = 0x2c; - sb->cfg_num_samples = 0x30; - sb->cfg_num_samples2 = 0x38; - sb->cfg_sample_rate = 0x44; - sb->cfg_channels = 0x4c; - sb->cfg_stream_type = 0x50; - sb->cfg_stream_name = 0x54; + sb->cfga_external_flag = 0x24; + sb->cfga_loop_flag = 0x28; + sb->cfga_group_id = 0x2c; + sb->cfga_num_samples = 0x30; + sb->cfga_num_samples2 = 0x38; + sb->cfga_sample_rate = 0x44; + sb->cfga_channels = 0x4c; + sb->cfga_stream_type = 0x50; + sb->cfga_stream_name = 0x54; sb->has_internal_names = 1; + + sb->cfgs_sequence_count = 0x28; //no layers return 1; } @@ -1528,20 +1521,22 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) { sb->section1_entry_size = 0x48; sb->section2_entry_size = 0x6c; - sb->cfg_external_flag = 0x18; - sb->cfg_loop_flag = 0x18; - sb->cfg_group_id = 0x18; - sb->cfg_channels = 0x20; - sb->cfg_sample_rate = 0x24; - sb->cfg_num_samples = 0x30; /* may be null */ - sb->cfg_num_samples2 = 0x38; /* may be null */ - sb->cfg_stream_name = 0x40; - sb->cfg_stream_type = 0x68; + sb->cfga_external_flag = 0x18; + sb->cfga_loop_flag = 0x18; + sb->cfga_group_id = 0x18; + sb->cfga_channels = 0x20; + sb->cfga_sample_rate = 0x24; + sb->cfga_num_samples = 0x30; /* may be null */ + sb->cfga_num_samples2 = 0x38; /* may be null */ + sb->cfga_stream_name = 0x40; + sb->cfga_stream_type = 0x68; sb->and_external_flag = 0x04; sb->and_loop_flag = 0x10; sb->and_group_id = 0x08; sb->shr_group_id = 3; + + sb->cfgs_sequence_count = 0x28; //no layers return 1; } @@ -1551,17 +1546,19 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) { sb->section1_entry_size = 0x6c; sb->section2_entry_size = 0x90; - sb->cfg_external_flag = 0x24; - sb->cfg_group_id = 0x28; - sb->cfg_loop_flag = 0x40; - sb->cfg_num_samples = 0x44; - sb->cfg_num_samples2 = 0x4c; - sb->cfg_sample_rate = 0x58; - sb->cfg_channels = 0x60; - sb->cfg_stream_type = 0x64; /* may contain garbage */ - sb->cfg_stream_name = 0x68; + sb->cfga_external_flag = 0x24; + sb->cfga_group_id = 0x28; + sb->cfga_loop_flag = 0x40; + sb->cfga_num_samples = 0x44; + sb->cfga_num_samples2 = 0x4c; + sb->cfga_sample_rate = 0x58; + sb->cfga_channels = 0x60; + sb->cfga_stream_type = 0x64; /* may contain garbage */ + sb->cfga_stream_name = 0x68; sb->has_internal_names = 1; + + sb->cfgs_sequence_count = 0x28; //no layers return 1; } @@ -1571,16 +1568,17 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) { sb->section1_entry_size = 0x6c; sb->section2_entry_size = 0x78; - sb->cfg_external_flag = 0x20; - sb->cfg_group_id = 0x24; - sb->cfg_loop_flag = 0x28; - sb->cfg_num_samples = 0x2c; - sb->cfg_num_samples2 = 0x34; - sb->cfg_sample_rate = 0x40; - sb->cfg_channels = 0x48; - sb->cfg_stream_type = 0x4c; - sb->cfg_stream_name = 0x50; + sb->cfga_external_flag = 0x20; + sb->cfga_group_id = 0x24; + sb->cfga_loop_flag = 0x28; + sb->cfga_num_samples = 0x2c; + sb->cfga_num_samples2 = 0x34; + sb->cfga_sample_rate = 0x40; + sb->cfga_channels = 0x48; + sb->cfga_stream_type = 0x4c; + sb->cfga_stream_name = 0x50; + sb->cfgs_sequence_count = 0x28; //no layers return 1; } @@ -1603,41 +1601,87 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) { sb->map_version = 2; - sb->cfg_external_flag = 0x24; - sb->cfg_loop_flag = 0x28; - sb->cfg_group_id = 0x2c; - sb->cfg_num_samples = 0x30; - sb->cfg_num_samples2 = 0x38; - sb->cfg_sample_rate = 0x44; - sb->cfg_channels = 0x4c; - sb->cfg_stream_type = 0x50; - sb->cfg_stream_name = 0x54; + sb->cfga_external_flag = 0x24; + sb->cfga_loop_flag = 0x28; + sb->cfga_group_id = 0x2c; + sb->cfga_num_samples = 0x30; + sb->cfga_num_samples2 = 0x38; + sb->cfga_sample_rate = 0x44; + sb->cfga_channels = 0x4c; + sb->cfga_stream_type = 0x50; + sb->cfga_stream_name = 0x54; sb->has_internal_names = 1; //has layers 06 (SC:E only) return 1; } - //todo check, bad external stream offsets? + //todo some .sb have bad external stream offsets (but not all, maybe unused garbage?) /* Brothers in Arms - D-Day (2006)(PSP)-bank */ if (sb->version == 0x0012000C && sb->platform == UBI_PSP && is_biadd_psp) { sb->section1_entry_size = 0x80; sb->section2_entry_size = 0x94; - sb->cfg_external_flag = 0x24; - sb->cfg_loop_flag = 0x28; - sb->cfg_group_id = 0x2c; - sb->cfg_num_samples = 0x30; - sb->cfg_num_samples2 = 0x38; - sb->cfg_sample_rate = 0x44; - sb->cfg_channels = 0x4c; - sb->cfg_stream_type = 0x50; - sb->cfg_stream_name = 0x54; + sb->cfga_external_flag = 0x24; + sb->cfga_loop_flag = 0x28; + sb->cfga_group_id = 0x2c; + sb->cfga_num_samples = 0x30; + sb->cfga_num_samples2 = 0x38; + sb->cfga_sample_rate = 0x44; + sb->cfga_channels = 0x4c; + sb->cfga_stream_type = 0x50; + sb->cfga_stream_name = 0x54; sb->has_internal_names = 1; return 1; } + /* Splinter Cell: Chaos Theory (2005)(PC)-map */ + if (sb->version == 0x00120012 && sb->platform == UBI_PC) { + sb->section1_entry_size = 0x68; + sb->section2_entry_size = 0x60; + + sb->map_version = 2; + + sb->cfga_external_flag = 0x24; + //sb->cfga_group_id = 0x28; + //sb->cfga_loop_flag = 0x2c; //todo test + sb->cfga_num_samples = 0x30; + sb->cfga_num_samples2 = 0x38; + sb->cfga_sample_rate = 0x44; + sb->cfga_channels = 0x4c; + sb->cfga_stream_type = 0x50; + sb->cfga_extra_name = 0x54; + + return 1; + } + + /* Myst IV: Revelation (2005)(PC)-bank */ + /* Splinter Cell: Chaos Theory (2005)(Xbox)-map */ + if (sb->version == 0x00120012 && sb->platform == UBI_XBOX) { + sb->section1_entry_size = 0x48; + sb->section2_entry_size = 0x4c; + + sb->map_version = 2; + + sb->cfga_external_flag = 0x18; + sb->cfga_group_id = 0x18; + sb->cfga_loop_flag = 0x18; + sb->cfga_num_samples = 0x1c; + sb->cfga_num_samples2 = 0x24; + sb->cfga_sample_rate = 0x30; + sb->cfga_channels = 0x38; + sb->cfga_stream_type = 0x3c; + sb->cfga_extra_name = 0x40; + + sb->and_external_flag = 0x0008; + sb->and_loop_flag = 0x0400; + sb->and_group_id = 0x0010; + sb->shr_group_id = 4; + //no layers + return 1; + } + /* Splinter Cell 3D (2011)(3DS)-map */ if (sb->version == 0x00130001 && sb->platform == UBI_3DS) { sb->section1_entry_size = 0x48; @@ -1645,15 +1689,15 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) { sb->map_version = 2; - sb->cfg_external_flag = 0x18; - sb->cfg_loop_flag = 0x18; - sb->cfg_group_id = 0x18; - sb->cfg_num_samples = 0x1c; - sb->cfg_num_samples2 = 0x24; - sb->cfg_sample_rate = 0x30; - sb->cfg_channels = 0x38; - sb->cfg_stream_type = 0x3c; - sb->cfg_extra_name = 0x40; + sb->cfga_external_flag = 0x18; + sb->cfga_loop_flag = 0x18; + sb->cfga_group_id = 0x18; + sb->cfga_num_samples = 0x1c; + sb->cfga_num_samples2 = 0x24; + sb->cfga_sample_rate = 0x30; + sb->cfga_channels = 0x38; + sb->cfga_stream_type = 0x3c; + sb->cfga_extra_name = 0x40; sb->and_external_flag = 0x04; sb->and_loop_flag = 0x10; @@ -1668,16 +1712,17 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) { sb->section1_entry_size = 0x68; sb->section2_entry_size = 0x78; - sb->cfg_external_flag = 0x2c; - sb->cfg_loop_flag = 0x30; - sb->cfg_group_id = 0x34; - sb->cfg_num_samples = 0x40; - sb->cfg_num_samples2 = 0x48; - sb->cfg_sample_rate = 0x54; - sb->cfg_channels = 0x5c; - sb->cfg_stream_type = 0x60; - sb->cfg_extra_name = 0x64; + sb->cfga_external_flag = 0x2c; + sb->cfga_loop_flag = 0x30; + sb->cfga_group_id = 0x34; + sb->cfga_num_samples = 0x40; + sb->cfga_num_samples2 = 0x48; + sb->cfga_sample_rate = 0x54; + sb->cfga_channels = 0x5c; + sb->cfga_stream_type = 0x60; + sb->cfga_extra_name = 0x64; + sb->cfgs_sequence_count = 0x2c; //no layers return 1; } @@ -1687,43 +1732,48 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) { sb->section1_entry_size = 0x48; sb->section2_entry_size = 0x5c; - sb->cfg_external_flag = 0x20; - sb->cfg_loop_flag = 0x20; - sb->cfg_group_id = 0x20; - sb->cfg_channels = 0x2c; - sb->cfg_sample_rate = 0x30; - sb->cfg_num_samples = 0x3c; - sb->cfg_num_samples2 = 0x44; - sb->cfg_extra_name = 0x4c; - sb->cfg_stream_type = 0x50; + sb->cfga_external_flag = 0x20; + sb->cfga_loop_flag = 0x20; + sb->cfga_group_id = 0x20; + sb->cfga_channels = 0x2c; + sb->cfga_sample_rate = 0x30; + sb->cfga_num_samples = 0x3c; + sb->cfga_num_samples2 = 0x44; + sb->cfga_extra_name = 0x4c; + sb->cfga_stream_type = 0x50; sb->and_external_flag = 0x04; sb->and_loop_flag = 0x10; sb->and_group_id = 0x08; sb->shr_group_id = 3; + + sb->cfgs_sequence_count = 0x2c; //no layers return 1; } /* Prince of Persia: The Two Thrones (2005)(Xbox)-bank */ + /* Far Cry Instincts (2005)(Xbox)-bank */ if (sb->version == 0x00150000 && sb->platform == UBI_XBOX) { sb->section1_entry_size = 0x48; sb->section2_entry_size = 0x58; - sb->cfg_external_flag = 0x20; - sb->cfg_loop_flag = 0x20; - sb->cfg_group_id = 0x20; - sb->cfg_num_samples = 0x28; - sb->cfg_num_samples2 = 0x30; - sb->cfg_sample_rate = 0x3c; - sb->cfg_channels = 0x44; - sb->cfg_stream_type = 0x48; - sb->cfg_extra_name = 0x4c; + sb->cfga_external_flag = 0x20; + sb->cfga_loop_flag = 0x20; + sb->cfga_group_id = 0x20; + sb->cfga_num_samples = 0x28; + sb->cfga_num_samples2 = 0x30; + sb->cfga_sample_rate = 0x3c; + sb->cfga_channels = 0x44; + sb->cfga_stream_type = 0x48; + sb->cfga_extra_name = 0x4c; sb->and_external_flag = 0x0008; sb->and_loop_flag = 0x0400; sb->and_group_id = 0x0010; sb->shr_group_id = 4; + + sb->cfgs_sequence_count = 0x2c; //no layers return 1; } @@ -1733,146 +1783,21 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) { sb->section1_entry_size = 0x68; sb->section2_entry_size = 0x6c; - sb->cfg_external_flag = 0x28; - //sb->cfg_group_id = 0x2c; /* assumed */ - sb->cfg_loop_flag = 0x30; - sb->cfg_num_samples = 0x3c; - sb->cfg_num_samples2 = 0x44; - sb->cfg_sample_rate = 0x50; - sb->cfg_channels = 0x58; - sb->cfg_stream_type = 0x5c; - sb->cfg_extra_name = 0x60; + sb->cfga_external_flag = 0x28; + //sb->cfga_group_id = 0x2c; /* assumed */ + sb->cfga_loop_flag = 0x30; + sb->cfga_num_samples = 0x3c; + sb->cfga_num_samples2 = 0x44; + sb->cfga_sample_rate = 0x50; + sb->cfga_channels = 0x58; + sb->cfga_stream_type = 0x5c; + sb->cfga_extra_name = 0x60; + sb->cfgs_sequence_count = 0x2c; //no layers return 1; } - /* Splinter Cell: Chaos Theory (2005)(PC)-map */ - if (sb->version == 0x00120012 && sb->platform == UBI_PC) { - sb->section1_entry_size = 0x68; - sb->section2_entry_size = 0x60; - - sb->map_version = 2; - - sb->cfg_external_flag = 0x24; - //sb->cfg_group_id = 0x28; - //sb->cfg_loop_flag = 0x2c; //todo test - sb->cfg_num_samples = 0x30; - sb->cfg_num_samples2 = 0x38; - sb->cfg_sample_rate = 0x44; - sb->cfg_channels = 0x4c; - sb->cfg_stream_type = 0x50; - sb->cfg_extra_name = 0x54; - - return 1; - } - - /* Splinter Cell: Chaos Theory (2005)(Xbox)-map */ - if (sb->version == 0x00120012 && sb->platform == UBI_XBOX) { - sb->section1_entry_size = 0x48; - sb->section2_entry_size = 0x4c; - - sb->map_version = 2; - - sb->cfg_external_flag = 0x18; - sb->cfg_group_id = 0x18; - sb->cfg_loop_flag = 0x18; - sb->cfg_num_samples = 0x1c; - sb->cfg_num_samples2 = 0x24; - sb->cfg_sample_rate = 0x30; - sb->cfg_channels = 0x38; - sb->cfg_stream_type = 0x3c; - sb->cfg_extra_name = 0x40; - - sb->and_external_flag = 0x0008; - sb->and_loop_flag = 0x0400; - sb->and_group_id = 0x0010; - sb->shr_group_id = 4; - //no layers - return 1; - } - -#if 0 - /* Far cry: Instincts - Evolution (2006)(Xbox)-bank */ - if (sb->version == 0x00170000 && sb->platform == UBI_XBOX) { - sb->section1_entry_size = 0x48; - sb->section2_entry_size = 0x6c; - - sb->cfg_external_flag = 0x20?; - sb->cfg_group_id = 0x20?; - sb->cfg_loop_flag = 0x20?; - sb->cfg_num_samples = 0x28; - sb->cfg_num_samples2 = 0x30?; - sb->cfg_sample_rate = 0x3c; - sb->cfg_channels = 0x44; - sb->cfg_stream_type = 0x48; - sb->cfg_extra_name = 0x58; - - ? - return 1; - } -#endif - - /* Red Steel (2006)(Wii)-bank */ - if (sb->version == 0x00180006 && sb->platform == UBI_WII) { - sb->section1_entry_size = 0x68; - sb->section2_entry_size = 0x6c; - - sb->cfg_external_flag = 0x28; - //sb->cfg_group_id = 0x2c; /* assumed */ - sb->cfg_loop_flag = 0x30; - sb->cfg_num_samples = 0x3c; - sb->cfg_num_samples2 = 0x44; - sb->cfg_sample_rate = 0x50; - sb->cfg_channels = 0x58; - sb->cfg_stream_type = 0x5c; - sb->cfg_extra_name = 0x60; - - return 1; - } - - /* Splinter Cell: Double Agent (2006)(PC)-map */ - if (sb->version == 0x00180006 && sb->platform == UBI_PC) { - sb->section1_entry_size = 0x68; - sb->section2_entry_size = 0x7c; - - sb->map_version = 3; - - sb->cfg_external_flag = 0x2c; - //sb->cfg_loop_flag = 0x30; //todo test - sb->cfg_group_id = 0x34; - sb->cfg_channels = 0x5c; - sb->cfg_sample_rate = 0x54; - sb->cfg_num_samples = 0x40; - sb->cfg_num_samples2 = 0x48; - sb->cfg_stream_type = 0x60; - sb->cfg_extra_name = 0x64; - - return 1; - } - - /* Splinter Cell: Double Agent (2006)(X360)-map */ - if (sb->version == 0x00180006 && sb->platform == UBI_X360) { - sb->section1_entry_size = 0x68; - sb->section2_entry_size = 0x78; - - sb->map_version = 3; - - sb->cfg_external_flag = 0x2c; - sb->cfg_group_id = 0x30; - sb->cfg_loop_flag = 0x34; - sb->cfg_channels = 0x5c; - sb->cfg_sample_rate = 0x54; - sb->cfg_num_samples = 0x40; - sb->cfg_num_samples2 = 0x48; - sb->cfg_stream_type = 0x60; - sb->cfg_extra_name = 0x64; - sb->cfg_xma_offset = 0x70; - - //has layer 06 - return 1; - } - /* Splinter Cell: Double Agent (2006)(Xbox)-map */ if (sb->version == 0x00160002 && sb->platform == UBI_XBOX) { sb->section1_entry_size = 0x48; @@ -1880,15 +1805,15 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) { sb->map_version = 3; - sb->cfg_external_flag = 0x20; - sb->cfg_group_id = 0x20; - sb->cfg_loop_flag = 0x20; - sb->cfg_num_samples = 0x28; - sb->cfg_num_samples2 = 0x30; - sb->cfg_sample_rate = 0x3c; - sb->cfg_channels = 0x44; - sb->cfg_stream_type = 0x48; - sb->cfg_extra_name = 0x4c; + sb->cfga_external_flag = 0x20; + sb->cfga_group_id = 0x20; + sb->cfga_loop_flag = 0x20; + sb->cfga_num_samples = 0x28; + sb->cfga_num_samples2 = 0x30; + sb->cfga_sample_rate = 0x3c; + sb->cfga_channels = 0x44; + sb->cfga_stream_type = 0x48; + sb->cfga_extra_name = 0x4c; sb->and_external_flag = 0x0008; sb->and_loop_flag = 0x0400; @@ -1905,15 +1830,15 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) { sb->map_version = 3; - sb->cfg_external_flag = 0x28; - sb->cfg_group_id = 0x2c; - sb->cfg_loop_flag = 0x30; - sb->cfg_num_samples = 0x3c; - sb->cfg_num_samples2 = 0x44; - sb->cfg_sample_rate = 0x50; - sb->cfg_channels = 0x58; - sb->cfg_stream_type = 0x5c; - sb->cfg_extra_name = 0x60; + sb->cfga_external_flag = 0x28; + sb->cfga_group_id = 0x2c; + sb->cfga_loop_flag = 0x30; + sb->cfga_num_samples = 0x3c; + sb->cfga_num_samples2 = 0x44; + sb->cfga_sample_rate = 0x50; + sb->cfga_channels = 0x58; + sb->cfga_stream_type = 0x5c; + sb->cfga_extra_name = 0x60; return 1; } @@ -1925,15 +1850,15 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) { sb->map_version = 3; - sb->cfg_external_flag = 0x20; - sb->cfg_loop_flag = 0x20; - sb->cfg_group_id = 0x20; - sb->cfg_channels = 0x28; - sb->cfg_sample_rate = 0x2c; - sb->cfg_num_samples = 0x34; - sb->cfg_num_samples2 = 0x38; - sb->cfg_extra_name = 0x44; - sb->cfg_stream_type = 0x48; + sb->cfga_external_flag = 0x20; + sb->cfga_loop_flag = 0x20; + sb->cfga_group_id = 0x20; + sb->cfga_channels = 0x28; + sb->cfga_sample_rate = 0x2c; + sb->cfga_num_samples = 0x34; + sb->cfga_num_samples2 = 0x38; + sb->cfga_extra_name = 0x44; + sb->cfga_stream_type = 0x48; sb->and_external_flag = 0x04; sb->and_loop_flag = 0x10; @@ -1943,6 +1868,28 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) { return 1; } + /* Far cry Instincts: Evolution (2006)(Xbox)-bank */ + if (sb->version == 0x00170000 && sb->platform == UBI_XBOX) { + sb->section1_entry_size = 0x48; + sb->section2_entry_size = 0x58; + + sb->cfga_external_flag = 0x20; + sb->cfga_group_id = 0x20; + sb->cfga_loop_flag = 0x20; + sb->cfga_num_samples = 0x28; + sb->cfga_num_samples2 = 0x30; + sb->cfga_sample_rate = 0x3c; + sb->cfga_channels = 0x44; + sb->cfga_stream_type = 0x48; + sb->cfga_extra_name = 0x4c; + + sb->and_external_flag = 0x0008; + sb->and_loop_flag = 0x0400; + sb->and_group_id = 0x0010; + sb->shr_group_id = 4; + return 1; + } + /* Open Season (2005)(PS2)-map [0x00180003] */ /* Open Season (2005)(PSP)-map [0x00180003] */ /* Prince of Persia: Rival Swords (2007)(PSP)-bank [0x00180005] */ @@ -1958,15 +1905,15 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) { sb->map_version = 3; - sb->cfg_external_flag = 0x20; - sb->cfg_loop_flag = 0x20; - sb->cfg_group_id = 0x20; - sb->cfg_channels = 0x28; - sb->cfg_sample_rate = 0x2c; - sb->cfg_num_samples = 0x34; - sb->cfg_num_samples2 = 0x3c; - sb->cfg_extra_name = 0x44; - sb->cfg_stream_type = 0x48; + sb->cfga_external_flag = 0x20; + sb->cfga_loop_flag = 0x20; + sb->cfga_group_id = 0x20; + sb->cfga_channels = 0x28; + sb->cfga_sample_rate = 0x2c; + sb->cfga_num_samples = 0x34; + sb->cfga_num_samples2 = 0x3c; + sb->cfga_extra_name = 0x44; + sb->cfga_stream_type = 0x48; sb->and_external_flag = 0x04; sb->and_loop_flag = 0x10; @@ -1976,22 +1923,86 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) { return 1; } - /* Prince of Persia: Rival Swords (2007)(Wii)-bank */ - if (sb->version == 0x00190003 && sb->platform == UBI_WII) { + /* Red Steel (2006)(Wii)-bank */ + if (sb->version == 0x00180006 && sb->platform == UBI_WII) { sb->section1_entry_size = 0x68; - sb->section2_entry_size = 0x70; + sb->section2_entry_size = 0x6c; - sb->cfg_external_flag = 0x28; - //sb->cfg_group_id = 0x2c; /* assumed */ - sb->cfg_loop_flag = 0x30; - sb->cfg_channels = 0x3c; - sb->cfg_sample_rate = 0x40; - sb->cfg_num_samples = 0x48; - sb->cfg_num_samples2 = 0x50; - sb->cfg_extra_name = 0x58; - sb->cfg_stream_type = 0x5c; + sb->cfga_external_flag = 0x28; + //sb->cfga_group_id = 0x2c; /* assumed */ + sb->cfga_loop_flag = 0x30; + sb->cfga_num_samples = 0x3c; + sb->cfga_num_samples2 = 0x44; + sb->cfga_sample_rate = 0x50; + sb->cfga_channels = 0x58; + sb->cfga_stream_type = 0x5c; + sb->cfga_extra_name = 0x60; - //has layer 06 (TMNT) + return 1; + } + + /* Splinter Cell: Double Agent (2006)(PC)-map */ + if (sb->version == 0x00180006 && sb->platform == UBI_PC) { + sb->section1_entry_size = 0x68; + sb->section2_entry_size = 0x7c; + + sb->map_version = 3; + + sb->cfga_external_flag = 0x2c; + //sb->cfga_loop_flag = 0x30; //todo test + sb->cfga_group_id = 0x34; + sb->cfga_channels = 0x5c; + sb->cfga_sample_rate = 0x54; + sb->cfga_num_samples = 0x40; + sb->cfga_num_samples2 = 0x48; + sb->cfga_stream_type = 0x60; + sb->cfga_extra_name = 0x64; + + return 1; + } + + /* Splinter Cell: Double Agent (2006)(X360)-map */ + if (sb->version == 0x00180006 && sb->platform == UBI_X360) { + sb->section1_entry_size = 0x68; + sb->section2_entry_size = 0x78; + + sb->map_version = 3; + + sb->cfga_external_flag = 0x2c; + sb->cfga_group_id = 0x30; + sb->cfga_loop_flag = 0x34; + sb->cfga_channels = 0x5c; + sb->cfga_sample_rate = 0x54; + sb->cfga_num_samples = 0x40; + sb->cfga_num_samples2 = 0x48; + sb->cfga_stream_type = 0x60; + sb->cfga_extra_name = 0x64; + sb->cfga_xma_offset = 0x70; + + //has layer 06 + return 1; + } + + /* TMNT (2007)(PSP)-map */ + if (sb->version == 0x00190001 && sb->platform == UBI_PSP) { + sb->section1_entry_size = 0x48; + sb->section2_entry_size = 0x58; + + sb->map_version = 3; + + sb->cfga_external_flag = 0x20; + sb->cfga_loop_flag = 0x20; + //sb->cfga_group_id = 0x20; /* assumed */ + sb->cfga_channels = 0x28; + sb->cfga_sample_rate = 0x2c; + sb->cfga_num_samples = 0x34; + sb->cfga_num_samples2 = 0x3c; + sb->cfga_stream_type = 0x48; + sb->cfga_extra_name = 0x44; + + sb->and_external_flag = 0x04; + sb->and_loop_flag = 0x10; + //has layer 06 return 1; } @@ -2000,15 +2011,15 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) { sb->section1_entry_size = 0x68; sb->section2_entry_size = 0x6c; - sb->cfg_external_flag = 0x28; - //sb->cfg_group_id = 0x2c; /* assumed */ - sb->cfg_loop_flag = 0x30; - sb->cfg_channels = 0x3c; - sb->cfg_sample_rate = 0x40; - sb->cfg_num_samples = 0x48; - sb->cfg_num_samples2 = 0x50; - sb->cfg_extra_name = 0x58; - sb->cfg_stream_type = 0x5c; + sb->cfga_external_flag = 0x28; + //sb->cfga_group_id = 0x2c; /* assumed */ + sb->cfga_loop_flag = 0x30; + sb->cfga_channels = 0x3c; + sb->cfga_sample_rate = 0x40; + sb->cfga_num_samples = 0x48; + sb->cfga_num_samples2 = 0x50; + sb->cfga_extra_name = 0x58; + sb->cfga_stream_type = 0x5c; return 1; } @@ -2018,15 +2029,15 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) { sb->section1_entry_size = 0x68; sb->section2_entry_size = 0x74; - sb->cfg_external_flag = 0x28; - sb->cfg_group_id = 0x2c; - sb->cfg_loop_flag = 0x30; - sb->cfg_channels = 0x3c; - sb->cfg_sample_rate = 0x40; - sb->cfg_num_samples = 0x48; - sb->cfg_num_samples2 = 0x50; - sb->cfg_extra_name = 0x58; - sb->cfg_stream_type = 0x5c; + sb->cfga_external_flag = 0x28; + sb->cfga_group_id = 0x2c; + sb->cfga_loop_flag = 0x30; + sb->cfga_channels = 0x3c; + sb->cfga_sample_rate = 0x40; + sb->cfga_num_samples = 0x48; + sb->cfga_num_samples2 = 0x50; + sb->cfga_extra_name = 0x58; + sb->cfga_stream_type = 0x5c; return 1; } @@ -2036,15 +2047,15 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) { sb->section1_entry_size = 0x48; sb->section2_entry_size = 0x5c; - sb->cfg_external_flag = 0x20; - sb->cfg_loop_flag = 0x20; - //sb->cfg_group_id = 0x20; /* assumed */ - sb->cfg_channels = 0x28; - sb->cfg_sample_rate = 0x2c; - sb->cfg_num_samples = 0x34; - sb->cfg_num_samples2 = 0x3c; - sb->cfg_extra_name = 0x44; - sb->cfg_stream_type = 0x48; + sb->cfga_external_flag = 0x20; + sb->cfga_loop_flag = 0x20; + //sb->cfga_group_id = 0x20; /* assumed */ + sb->cfga_channels = 0x28; + sb->cfga_sample_rate = 0x2c; + sb->cfga_num_samples = 0x34; + sb->cfga_num_samples2 = 0x3c; + sb->cfga_extra_name = 0x44; + sb->cfga_stream_type = 0x48; sb->and_external_flag = 0x04; sb->and_loop_flag = 0x10; @@ -2057,40 +2068,36 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) { sb->section1_entry_size = 0x68; sb->section2_entry_size = 0x70; - sb->cfg_external_flag = 0x28; - //sb->cfg_group_id = 0x2c; /* assumed */ - sb->cfg_loop_flag = 0x30; - sb->cfg_channels = 0x3c; - sb->cfg_sample_rate = 0x40; - sb->cfg_num_samples = 0x48; - sb->cfg_num_samples2 = 0x50; - sb->cfg_stream_type = 0x5c; - sb->cfg_extra_name = 0x58; - sb->cfg_xma_offset = 0x6c; + sb->cfga_external_flag = 0x28; + //sb->cfga_group_id = 0x2c; /* assumed */ + sb->cfga_loop_flag = 0x30; + sb->cfga_channels = 0x3c; + sb->cfga_sample_rate = 0x40; + sb->cfga_num_samples = 0x48; + sb->cfga_num_samples2 = 0x50; + sb->cfga_extra_name = 0x58; + sb->cfga_stream_type = 0x5c; + sb->cfga_xma_offset = 0x6c; return 1; } - /* TMNT (2007)(PSP)-map */ - if (sb->version == 0x00190001 && sb->platform == UBI_PSP) { - sb->section1_entry_size = 0x48; - sb->section2_entry_size = 0x58; + /* Prince of Persia: Rival Swords (2007)(Wii)-bank */ + if (sb->version == 0x00190003 && sb->platform == UBI_WII) { + sb->section1_entry_size = 0x68; + sb->section2_entry_size = 0x70; - sb->map_version = 3; + sb->cfga_external_flag = 0x28; + //sb->cfga_group_id = 0x2c; /* assumed */ + sb->cfga_loop_flag = 0x30; + sb->cfga_channels = 0x3c; + sb->cfga_sample_rate = 0x40; + sb->cfga_num_samples = 0x48; + sb->cfga_num_samples2 = 0x50; + sb->cfga_extra_name = 0x58; + sb->cfga_stream_type = 0x5c; - sb->cfg_external_flag = 0x20; - sb->cfg_loop_flag = 0x20; - //sb->cfg_group_id = 0x20; /* assumed */ - sb->cfg_channels = 0x28; - sb->cfg_sample_rate = 0x2c; - sb->cfg_num_samples = 0x34; - sb->cfg_num_samples2 = 0x3c; - sb->cfg_stream_type = 0x48; - sb->cfg_extra_name = 0x44; - - sb->and_external_flag = 0x04; - sb->and_loop_flag = 0x10; - //has layer 06 + //has layer 06 (TMNT) return 1; } @@ -2099,15 +2106,15 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) { sb->section1_entry_size = 0x68; sb->section2_entry_size = 0x74; - sb->cfg_external_flag = 0x28; - //sb->cfg_group_id = 0x2c; /* assumed */ - sb->cfg_loop_flag = 0x30; - sb->cfg_channels = 0x3c; - sb->cfg_sample_rate = 0x40; - sb->cfg_num_samples = 0x48; - sb->cfg_num_samples2 = 0x50; - sb->cfg_extra_name = 0x58; - sb->cfg_stream_type = 0x5c; + sb->cfga_external_flag = 0x28; + //sb->cfga_group_id = 0x2c; /* assumed */ + sb->cfga_loop_flag = 0x30; + sb->cfga_channels = 0x3c; + sb->cfga_sample_rate = 0x40; + sb->cfga_num_samples = 0x48; + sb->cfga_num_samples2 = 0x50; + sb->cfga_extra_name = 0x58; + sb->cfga_stream_type = 0x5c; return 1; } @@ -2120,15 +2127,15 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) { sb->map_version = 3; - sb->cfg_external_flag = 0x28; - sb->cfg_group_id = 0x2c; - sb->cfg_loop_flag = 0x30; - sb->cfg_channels = 0x3c; - sb->cfg_sample_rate = 0x40; - sb->cfg_num_samples = 0x48; - sb->cfg_num_samples2 = 0x50; - sb->cfg_extra_name = 0x58; - sb->cfg_stream_type = 0x5c; + sb->cfga_external_flag = 0x28; + sb->cfga_group_id = 0x2c; + sb->cfga_loop_flag = 0x30; + sb->cfga_channels = 0x3c; + sb->cfga_sample_rate = 0x40; + sb->cfga_num_samples = 0x48; + sb->cfga_num_samples2 = 0x50; + sb->cfga_extra_name = 0x58; + sb->cfga_stream_type = 0x5c; return 1; } @@ -2138,16 +2145,16 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) { sb->section1_entry_size = 0x68; sb->section2_entry_size = 0x70; - sb->cfg_external_flag = 0x28; - //sb->cfg_group_id = 0x2c; /* assumed */ - sb->cfg_loop_flag = 0x30; - sb->cfg_channels = 0x3c; - sb->cfg_sample_rate = 0x40; - sb->cfg_num_samples = 0x48; - sb->cfg_num_samples2 = 0x50; - sb->cfg_stream_type = 0x5c; - sb->cfg_extra_name = 0x58; - sb->cfg_xma_offset = 0x6c; + sb->cfga_external_flag = 0x28; + //sb->cfga_group_id = 0x2c; /* assumed */ + sb->cfga_loop_flag = 0x30; + sb->cfga_channels = 0x3c; + sb->cfga_sample_rate = 0x40; + sb->cfga_num_samples = 0x48; + sb->cfga_num_samples2 = 0x50; + sb->cfga_stream_type = 0x5c; + sb->cfga_extra_name = 0x58; + sb->cfga_xma_offset = 0x6c; return 1; } @@ -2159,15 +2166,15 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) { sb->map_version = 3; - sb->cfg_external_flag = 0x20; - sb->cfg_loop_flag = 0x20; - //sb->cfg_group_id = 0x20; /* assumed */ - sb->cfg_channels = 0x28; - sb->cfg_sample_rate = 0x2c; - sb->cfg_num_samples = 0x34; - sb->cfg_num_samples2 = 0x3c; - sb->cfg_extra_name = 0x44; - sb->cfg_stream_type = 0x48; + sb->cfga_external_flag = 0x20; + sb->cfga_loop_flag = 0x20; + //sb->cfga_group_id = 0x20; /* assumed */ + sb->cfga_channels = 0x28; + sb->cfga_sample_rate = 0x2c; + sb->cfga_num_samples = 0x34; + sb->cfga_num_samples2 = 0x3c; + sb->cfga_extra_name = 0x44; + sb->cfga_stream_type = 0x48; sb->and_external_flag = 0x04; sb->and_loop_flag = 0x10; @@ -2182,15 +2189,15 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) { sb->map_version = 3; - sb->cfg_external_flag = 0x20; - sb->cfg_loop_flag = 0x20; - //sb->cfg_group_id = 0x20; /* assumed */ - sb->cfg_channels = 0x28; - sb->cfg_sample_rate = 0x30; - sb->cfg_num_samples = 0x38; - sb->cfg_num_samples2 = 0x40; - sb->cfg_extra_name = 0x48; - sb->cfg_stream_type = 0x4c; + sb->cfga_external_flag = 0x20; + sb->cfga_loop_flag = 0x20; + //sb->cfga_group_id = 0x20; /* assumed */ + sb->cfga_channels = 0x28; + sb->cfga_sample_rate = 0x30; + sb->cfga_num_samples = 0x38; + sb->cfga_num_samples2 = 0x40; + sb->cfga_extra_name = 0x48; + sb->cfga_stream_type = 0x4c; sb->and_external_flag = 0x04; sb->and_loop_flag = 0x20; @@ -2205,15 +2212,15 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) { sb->map_version = 3; - sb->cfg_external_flag = 0x28; - sb->cfg_group_id = 0x30; - sb->cfg_loop_flag = 0x34; - sb->cfg_channels = 0x44; - sb->cfg_sample_rate = 0x4c; - sb->cfg_num_samples = 0x54; - sb->cfg_num_samples2 = 0x5c; - sb->cfg_extra_name = 0x64; - sb->cfg_stream_type = 0x68; + sb->cfga_external_flag = 0x28; + sb->cfga_group_id = 0x30; + sb->cfga_loop_flag = 0x34; + sb->cfga_channels = 0x44; + sb->cfga_sample_rate = 0x4c; + sb->cfga_num_samples = 0x54; + sb->cfga_num_samples2 = 0x5c; + sb->cfga_extra_name = 0x64; + sb->cfga_stream_type = 0x68; //has layer 06 return 1; @@ -2222,3 +2229,261 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) { VGM_LOG("UBI SB: unknown SB/SM version+platform for %08x\n", sb->version); return 0; } + +/* Donald Duck: Goin' Quackers (2002)(GC)-map */ +/* - type header: + * 0x1c: sample rate * layers + * 0x20: layers + * 0x30: external flag? + * 0x34: external name + * 0x44: stream offset + * 0x48: original rate * layers? + * 0x4c: stream size (not including padding) + * no samples + * + * - layer header + * - blocked data + * 0x02 see below (Ubi IMA v2 though) + */ + +/* 0x0d layer [Splinter Cell] */ +/* - type header: + * 0x18: stream offset? + * 0x20: (sample rate * layers) + 1? + * 0x24: layers/channels? + * 0x30: external flag + * 0x34: external name + * 0x5C: stream offset + * 0x64: stream size (not including padding) + * 0x78/7c: codec? + * + * - layer header at stream_offset: + * 0x00: version? (0x00000002) + * 0x04: layers + * 0x08: stream size (not including padding) + * 0x0c: size? + * 0x10: count? + * 0x14: min block size? + * + * - blocked data (unlike other layers, first block data is standard Ubi IMA headers, v3): + * 0x00: block number (from 0x01 to block_count) + * 0x04: current offset (within stream_offset) + * - per layer: + * 0x00: layer data size (varies between blocks, and one layer may have more than other, even the header) + */ + + +/* Rainbow Six 3 */ +/* Prince of Persia: Sands of Time (all) 0x000A0004 */ +/* Batman: Rise of Sin Tzu (2003)(GC)-map - 0x000A0002 */ +/* - type header (bizarrely but thankfully doesn't change between platforms): + * 0x1c: sample rate * layers + * 0x20: layers/channels? + * 0x2c: external flag? + * 0x30: external name + * 0x58: stream offset + * 0x5c: original rate * layers? + * 0x60: stream size (not including padding) + * 0x64: number of samples + * + * - layer header at stream_offset (BE on GC): + * 0x00: version? (0x00000004) + * 0x04: layers + * 0x08: stream size (not including padding) + * 0x0c: blocks count + * 0x10: block header size + * 0x14: block size + * 0x18: ? + * 0x1c: size of next section + * - per layer: + * 0x00: layer header size + * codec header per layer + * 0x00~0x20: standard Ubi IMA header (version 0x05, LE) + * + * - blocked data: + * 0x00: block number (from 0x01 to block_count) + * 0x04: current offset (within stream_offset) + * 0x08: always 0x03 + * - per layer: + * 0x00: layer data size (varies between blocks, and one layer may have more than other) + */ + +/* Splinter Cell: Essentials (PSP)-map 0x0012000C */ +/* - type header: + * 0x08: header extra offset + * 0x1c: layers + * 0x28: external flag? + * 0x2c: external flag? + * 0x30: stream name + * 0x5c: sample rate * layers + * 0x60: stream size + * 0x64: stream offset? + * + * - in header extra offset (style 0x10) + * 0x00: sample rate + * 0x04: 16? + * 0x08: channels? + * 0x0c: codec? + * + * - layer header at stream_offset: + * 0x00: version (0x00000007) + * 0x04: config? + * 0x08: layers + * 0x0c: stream size + * 0x10: blocks count + * 0x14: block header size + * 0x18: next block size + * - per layer: + * 0x00: approximate layer data size per block + * - per layer + * 0x00~0x0c: weird header thing? -1/0/0c... + * + * - blocked data: + * 0x00: block number (from 0x01 to block_count) + * 0x04: current offset (within stream_offset) + * 0x08: always 0x03 + * - per layer: + * 0x00: layer data size (varies between blocks, and one layer may have more than other) + */ + +/* Splinter Cell: Double Agent (2006)(X360)-map 0x00180006 */ +/* - type header: + * 0x08: header extra offset + * 0x20: layers + * 0x28: external flag? + * 0x30: external flag? + * 0x34: sample rate * layers + * 0x38: stream size + * 0x3c: stream offset + * 0x44: name extra offset + * + * - in header extra offset + * style 0x10 (codec 05 XMA), possible total size 0x34 + * + * - layer header at stream_offset: + * version 0x000C0008 same as 0x000B0008, but codec header size is 0 + * + * - blocked data: + * version same as 0x000B0008 (including mini XMA header + weird tables) + */ + +/* Splinter Cell 3D (2011)(3DS)-map 0x00130001 */ +/* - type header: + * 0x08: header extra offset + * 0x10: layers + * 0x28: stream size + * 0x30: stream offset + * 0x34: name extra offset + * + * - in header extra offset + * style 0x10 (size 0x18?) + * + * - layer header at stream_offset: + * same as 0x00000007 but weird header thing is 0x00~0x08, has header sizes after that + * + * - blocked data: + * same as 0x00000007 + */ + +/* TMNT (2007)(PS2)-bank 0x00190002 */ +/* - type header: + * 0x08: header extra offset + * 0x1c: external flag? + * 0x20: layers + * 0x28: sample rate * layers + * 0x2c: stream size + * 0x30: stream offset + * 0x38: name extra offset + * + * - in header extra offset (style 0x0c) + * 0x00: sample rate + * 0x04: channels + * 0x08: codec + * + * - layer header at stream_offset: + * 0x00: version? (0x000B0008) + * 0x04: config? (0x00/0x0e/0x0b/etc) + * 0x08: layers + * 0x0c: blocks count + * 0x10: block header size + * 0x14: size of header sizes + * 0x18: next block size + * - per layer: + * 0x00: layer header size + * - per layer (if layer header size > 0) + * 0x00~0x20: standard Ubi IMA header (version 0x05), PCM data + * + * - blocked data: + * 0x00: always 0x03 + * 0x04: next block size + * - per layer: + * 0x00: layer data size (varies between blocks, and one layer may have more than other) + */ + +/* Open Season (2005)(PS2)-map 0x00180003 */ +/* Rainbow Six Vegas (2007)(PSP)-bank 0x00180006 */ +/* Star Wars - Lethal Alliance (2006)(PSP)-map 0x00180007 */ +/* - type header: + * 0x0c: header extra offset + * 0x20: layers + * 0x2c: stream size + * 0x30: stream offset + * 0x38: name extra offset + * + * - in header extra offset + * style 0x10 (codec 03=Ubi, 01=PCM16LE in SW:LA/RS:V) + * - layer header at stream_offset: + * - blocked data: + * version 0x000B0008 + */ + +/* TMNT (2007)(PSP)-map 0x00190001 */ +/* - type header: + * 0x0c: header extra offset + * 0x20: layers + * 0x24: total channels? + * 0x28: sample rate * layers? + * 0x2c: stream size + * 0x30: stream offset + * 0x38: name extra offset + * + * - in header extra offset + * style 0x0c + * - layer header at stream_offset: + * - blocked data: + * version 0x000B0008, but codec header size is 0 + */ + +/* TMNT (2007)(GC)-bank 0x00190002 */ +/* Surf's Up (PS3)-bank 0x00190005 */ +/* - type header: + * 0x08: header extra offset + * 0x1c: external flag? + * 0x20: layers + * 0x2c: external flag? (would match header 01) + * 0x30: sample rate * layers + * 0x34: stream size + * 0x38: stream offset + * 0x40: name extra offset + * + * - in header extra offset + * style 0x0c + * - layer header at stream_offset: + * - blocked data: + * version 0x000B0008 + */ + +/* Splinter Cell Classic Trilogy HD (2011)(PS3)-map 0x001d0000 */ +/* - type header: + * 0x0c: header extra offset + * 0x20: layers + * 0x44: stream size + * 0x48: stream offset + * 0x54: name extra offset + * + * - in header extra offset + * style 0x0c + * - layer header at stream_offset: + * - blocked data: + * version 0x000B0008, but codec header size is 0 + */ diff --git a/src/meta/vag.c b/src/meta/vag.c index e88a78a5..b4f2a983 100644 --- a/src/meta/vag.c +++ b/src/meta/vag.c @@ -19,8 +19,10 @@ VGMSTREAM * init_vgmstream_vag(STREAMFILE *streamFile) { * .swag: Frantix (PSP) * .str: Ben10 Galactic Racing * .vig: MX vs. ATV Untamed (PS2) - * .l/r: Crash Nitro Kart (PS2), Gradius V (PS2) */ - if ( !check_extensions(streamFile,"vag,swag,str,vig,l,r") ) + * .l/r: Crash Nitro Kart (PS2), Gradius V (PS2) + * .vas: Kingdom Hearts II (PS2) + * .khv: fake for .vas */ + if ( !check_extensions(streamFile,"vag,swag,str,vig,l,r,vas,khv") ) goto fail; /* check VAG Header */ @@ -112,7 +114,7 @@ VGMSTREAM * init_vgmstream_vag(STREAMFILE *streamFile) { interleave = 0x10; loop_flag = 0; } - else if (check_extensions(streamFile,"swag")) { /* algo "VAGp" at (file_size / channels) */ + else if (check_extensions(streamFile,"swag")) { /* also "VAGp" at (file_size / channels) */ /* Frantix (PSP) */ start_offset = 0x40; /* channel_size ignores empty frame */ channel_count = 2; @@ -188,6 +190,19 @@ VGMSTREAM * init_vgmstream_vag(STREAMFILE *streamFile) { channel_size = channel_size / channel_count; loop_flag = ps_find_loop_offsets(streamFile, start_offset, channel_size*channel_count, channel_count, interleave, &loop_start_sample, &loop_end_sample); } + else if (version == 0x00000004 && channel_size == file_size - 0x60 && read_32bitBE(0x1c, streamFile) != 0) { /* also .vas */ + /* Kingdom Hearts II (PS2) */ + start_offset = 0x60; + interleave = 0x10; + + loop_start_sample = read_32bitBE(0x14,streamFile); + loop_end_sample = read_32bitBE(0x18,streamFile); + loop_flag = (loop_end_sample > 0); /* maybe at 0x1d */ + channel_count = read_8bit(0x1e,streamFile); + /* 0x1f: possibly volume */ + channel_size = channel_size / channel_count; + /* mono files also have channel/volume, but start at 0x30 and are probably named .vag */ + } else { /* standard PS1/PS2/PS3 .vag [Ecco the Dolphin (PS2), Legasista (PS3)] */ start_offset = 0x30; diff --git a/src/vgmstream.c b/src/vgmstream.c index a71fa9f0..a86c9835 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -253,7 +253,6 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = { init_vgmstream_ps2_smpl, init_vgmstream_ps2_msa, init_vgmstream_ps2_voi, - init_vgmstream_ps2_khv, init_vgmstream_ngc_rkv, init_vgmstream_dsp_ddsp, init_vgmstream_p3d, @@ -279,6 +278,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = { init_vgmstream_sqex_scd, init_vgmstream_ngc_nst_dsp, init_vgmstream_baf, + init_vgmstream_baf_badrip, init_vgmstream_ps3_msf, init_vgmstream_nub_vag, init_vgmstream_ps3_past, @@ -460,6 +460,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = { init_vgmstream_imc, init_vgmstream_imc_container, init_vgmstream_smp, + init_vgmstream_gin, /* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */ init_vgmstream_txth, /* proper parsers should supersede TXTH, once added */ @@ -1142,6 +1143,7 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) { case coding_SNDS_IMA: case coding_OTNS_IMA: case coding_UBI_IMA: + case coding_OKI16: return 1; case coding_IMA_int: case coding_DVI_IMA_int: @@ -1188,7 +1190,9 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) { case coding_EA_XA_V2: case coding_MAXIS_XA: return 28; - case coding_EA_XAS: + case coding_EA_XAS_V0: + return 32; + case coding_EA_XAS_V1: return 128; case coding_MSADPCM: @@ -1323,6 +1327,7 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) { case coding_ALP_IMA: case coding_FFTA2_IMA: case coding_PCFX: + case coding_OKI16: return 0x01; case coding_MS_IMA: case coding_RAD_IMA: @@ -1370,7 +1375,9 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) { return 0x0F*vgmstream->channels; case coding_EA_XA_V2: return 0; /* variable (ADPCM frames of 0x0f or PCM frames of 0x3d) */ - case coding_EA_XAS: + case coding_EA_XAS_V0: + return 0xF+0x02+0x02; + case coding_EA_XAS_V1: return 0x4c*vgmstream->channels; case coding_MSADPCM: @@ -1706,9 +1713,15 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to vgmstream->channels,vgmstream->samples_into_block,samples_to_do, ch); } break; - case coding_EA_XAS: + case coding_EA_XAS_V0: for (ch = 0; ch < vgmstream->channels; ch++) { - decode_ea_xas(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + decode_ea_xas_v0(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do, ch); + } + break; + case coding_EA_XAS_V1: + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_ea_xas_v1(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, vgmstream->channels,vgmstream->samples_into_block,samples_to_do, ch); } break; @@ -2040,6 +2053,12 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to vgmstream->channels,vgmstream->samples_into_block,samples_to_do, vgmstream->codec_config); } break; + case coding_OKI16: + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_oki16(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do, ch); + } + break; case coding_EA_MT: for (ch = 0; ch < vgmstream->channels; ch++) { diff --git a/src/vgmstream.h b/src/vgmstream.h index 5d9bb87b..dfc1477d 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -106,7 +106,8 @@ typedef enum { coding_EA_XA_int, /* Electronic Arts EA-XA ADPCM v1 (mono/interleave) */ coding_EA_XA_V2, /* Electronic Arts EA-XA ADPCM v2 */ coding_MAXIS_XA, /* Maxis EA-XA ADPCM */ - coding_EA_XAS, /* Electronic Arts EA-XAS ADPCM */ + coding_EA_XAS_V0, /* Electronic Arts EA-XAS ADPCM v0 */ + coding_EA_XAS_V1, /* Electronic Arts EA-XAS ADPCM v1 */ coding_IMA, /* IMA ADPCM (stereo or mono, low nibble first) */ coding_IMA_int, /* IMA ADPCM (mono/interleave, low nibble first) */ @@ -152,6 +153,7 @@ typedef enum { coding_ASF, /* Argonaut ASF 4-bit ADPCM */ coding_XMD, /* Konami XMD 4-bit ADPCM */ coding_PCFX, /* PC-FX 4-bit ADPCM */ + coding_OKI16, /* OKI 4-bit ADPCM with 16-bit output */ /* others */ coding_SDX2, /* SDX2 2:1 Squareroot-Delta-Exact compression DPCM */ @@ -532,7 +534,6 @@ typedef enum { meta_PS2_SMPL, /* Homura */ meta_PS2_MSA, /* Psyvariar -Complete Edition- */ meta_PS2_VOI, /* RAW Danger (Zettaizetsumei Toshi 2 - Itetsuita Kiokutachi) [PS2] */ - meta_PS2_KHV, /* Kingdom Hearts 2 VAG streams */ meta_P3D, /* Prototype P3D */ meta_PS2_TK1, /* Tekken (NamCollection) */ meta_NGC_RKV, /* Legacy of Kain - Blood Omen 2 (GC) */ @@ -712,6 +713,7 @@ typedef enum { meta_DSP_ADPCMX, meta_OGG_OPUS, meta_IMC, + meta_GIN, } meta_t;