From a3645e9f69b45fa4c4b05d59f9faff4c90b619cc Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 1 May 2022 12:10:56 +0200 Subject: [PATCH 01/10] Add .switch extension [Ikinari Maou (Switch)] --- src/formats.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/formats.c b/src/formats.c index 6739d6aa..e8b501e6 100644 --- a/src/formats.c +++ b/src/formats.c @@ -522,6 +522,7 @@ static const char* extension_list[] = { "swag", "swav", "swd", + "switch", //txth/reserved (.m4a-x.switch) [Ikinari Maou (Switch)] "switch_audio", "sx", "sxd", From cdc57538473fa71645d93b16bda82efdf0b74c63 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 1 May 2022 12:13:02 +0200 Subject: [PATCH 02/10] Add PCM_FLOAT_LE codec to TXTH --- doc/TXTH.md | 3 ++ src/meta/txth.c | 81 +++++++++++++++++++++++++++---------------------- 2 files changed, 47 insertions(+), 37 deletions(-) diff --git a/doc/TXTH.md b/doc/TXTH.md index b9b4dcbf..c442e001 100644 --- a/doc/TXTH.md +++ b/doc/TXTH.md @@ -92,6 +92,9 @@ as explained below, but often will use default values. Accepted codec strings: # * Variation with modified encoding # - PCM8_U_int PCM 8-bit unsigned (interleave block) # * Variation with modified encoding +# - PCM_FLOAT_LE PCM 32-bit float little endian +# * For few rare games [Ikinari Maou (Switch)] +# * Interleave is multiple of 0x4 (default) # - IMA IMA ADPCM (mono/stereo) # * For some PC games, and rarely consoles # * Special interleave is multiple of 0x1, often +0x80 diff --git a/src/meta/txth.c b/src/meta/txth.c index e2354841..da3efc69 100644 --- a/src/meta/txth.c +++ b/src/meta/txth.c @@ -46,6 +46,7 @@ typedef enum { XA, XA_EA, CP_YM, + PCM_FLOAT_LE, UNKNOWN = 99, } txth_codec_t; @@ -213,13 +214,14 @@ VGMSTREAM* init_vgmstream_txth(STREAMFILE* sf) { if (txth.interleave == 0) { uint32_t interleave = 0; switch(txth.codec) { - case PSX: interleave = 0x10; break; - case PSX_bf: interleave = 0x10; break; - case NGC_DSP: interleave = 0x08; break; - case PCM16LE: interleave = 0x02; break; - case PCM16BE: interleave = 0x02; break; - case PCM8: interleave = 0x01; break; - case PCM8_U: interleave = 0x01; break; + case PSX: interleave = 0x10; break; + case PSX_bf: interleave = 0x10; break; + case NGC_DSP: interleave = 0x08; break; + case PCM16LE: interleave = 0x02; break; + case PCM16BE: interleave = 0x02; break; + case PCM8: interleave = 0x01; break; + case PCM8_U: interleave = 0x01; break; + case PCM_FLOAT_LE: interleave = 0x04; break; default: break; } @@ -229,26 +231,27 @@ VGMSTREAM* init_vgmstream_txth(STREAMFILE* sf) { /* type to coding conversion */ switch (txth.codec) { - case PSX: coding = coding_PSX; break; - case XBOX: coding = coding_XBOX_IMA; break; - case NGC_DTK: coding = coding_NGC_DTK; break; - case PCM16BE: coding = coding_PCM16BE; break; - case PCM16LE: coding = coding_PCM16LE; break; - case PCM8: coding = coding_PCM8; break; - case SDX2: coding = coding_SDX2; break; - case DVI_IMA: coding = coding_DVI_IMA; break; + case PSX: coding = coding_PSX; break; + case XBOX: coding = coding_XBOX_IMA; break; + case NGC_DTK: coding = coding_NGC_DTK; break; + case PCM16BE: coding = coding_PCM16BE; break; + case PCM16LE: coding = coding_PCM16LE; break; + case PCM8: coding = coding_PCM8; break; + case PCM_FLOAT_LE: coding = coding_PCMFLOAT; break; + case SDX2: coding = coding_SDX2; break; + case DVI_IMA: coding = coding_DVI_IMA; break; #ifdef VGM_USE_MPEG - case MPEG: coding = coding_MPEG_layer3; break; /* we later find out exactly which */ + case MPEG: coding = coding_MPEG_layer3; break; /* we later find out exactly which */ #endif - case IMA: coding = coding_IMA; break; - case AICA: coding = coding_AICA; break; - case MSADPCM: coding = coding_MSADPCM; break; - case NGC_DSP: coding = coding_NGC_DSP; break; - case PCM8_U_int: coding = coding_PCM8_U_int; break; - case PSX_bf: coding = coding_PSX_badflags; break; - case MS_IMA: coding = coding_MS_IMA; break; - case PCM8_U: coding = coding_PCM8_U; break; - case APPLE_IMA4: coding = coding_APPLE_IMA4; break; + case IMA: coding = coding_IMA; break; + case AICA: coding = coding_AICA; break; + case MSADPCM: coding = coding_MSADPCM; break; + case NGC_DSP: coding = coding_NGC_DSP; break; + case PCM8_U_int: coding = coding_PCM8_U_int; break; + case PSX_bf: coding = coding_PSX_badflags; break; + case MS_IMA: coding = coding_MS_IMA; break; + case PCM8_U: coding = coding_PCM8_U; break; + case APPLE_IMA4: coding = coding_APPLE_IMA4; break; #ifdef VGM_USE_FFMPEG case ATRAC3: case ATRAC3PLUS: @@ -256,19 +259,19 @@ VGMSTREAM* init_vgmstream_txth(STREAMFILE* sf) { case XMA2: case AC3: case AAC: - case FFMPEG: coding = coding_FFmpeg; break; + case FFMPEG: coding = coding_FFmpeg; break; #endif - 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; - case OKI4S: coding = coding_OKI4S; break; - case TGC: coding = coding_TGC; break; - case ASF: coding = coding_ASF; break; - case EAXA: coding = coding_EA_XA; break; - case XA: coding = coding_XA; break; - case XA_EA: coding = coding_XA_EA; break; - case CP_YM: coding = coding_CP_YM; break; + 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; + case OKI4S: coding = coding_OKI4S; break; + case TGC: coding = coding_TGC; break; + case ASF: coding = coding_ASF; break; + case EAXA: coding = coding_EA_XA; break; + case XA: coding = coding_XA; break; + case XA_EA: coding = coding_XA_EA; break; + case CP_YM: coding = coding_CP_YM; break; default: goto fail; } @@ -305,6 +308,7 @@ VGMSTREAM* init_vgmstream_txth(STREAMFILE* sf) { case coding_PCM16BE: case coding_PCM8: case coding_PCM8_U: + case coding_PCMFLOAT: case coding_PCM4: case coding_PCM4_U: case coding_SDX2: @@ -963,6 +967,7 @@ static txth_codec_t parse_codec(txth_header* txth, const char* val) { else if (is_string(val,"XA")) return XA; else if (is_string(val,"XA_EA")) return XA_EA; else if (is_string(val,"CP_YM")) return CP_YM; + else if (is_string(val,"PCM_FLOAT_LE")) return PCM_FLOAT_LE; /* special handling */ else if (is_string(val,"name_value")) return txth->name_values[0]; else if (is_string(val,"name_value1")) return txth->name_values[0]; @@ -2039,6 +2044,8 @@ static int get_bytes_to_samples(txth_header* txth, uint32_t bytes) { case PCM8_U_int: case PCM8_U: return pcm_bytes_to_samples(bytes, txth->channels, 8); + case PCM_FLOAT_LE: + return pcm_bytes_to_samples(bytes, txth->channels, 32); case PCM4: case PCM4_U: case TGC: From 2955ab3a813b806d30bbab0b5f340f8929fd788b Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 1 May 2022 12:13:11 +0200 Subject: [PATCH 03/10] Fix some SSPF .ssp [Metal Gear Solid 4 (PS3)] --- src/meta/sspf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/meta/sspf.c b/src/meta/sspf.c index 2929fa4e..da9f1cf6 100644 --- a/src/meta/sspf.c +++ b/src/meta/sspf.c @@ -21,7 +21,7 @@ VGMSTREAM* init_vgmstream_sspf(STREAMFILE* sf) { goto fail; /* extra check to ignore .spc, that are a RAM pack of .ssp with a ~0x800 table at the end */ - file_size = read_u32be(0x08, sf) + 0x08; /* without padding */ + file_size = read_u32be(0x08, sf); /* without padding */ pad_size = 0; if (file_size % 0x800) /* add padding */ pad_size = 0x800 - (file_size % 0x800); From 2a6dd8d782b3ef181ba7dee04774902289d62054 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 1 May 2022 12:17:57 +0200 Subject: [PATCH 04/10] Add ADM3 .wem [MotoGP 21 (PC)] --- src/formats.c | 1 + src/libvgmstream.vcxproj | 1 + src/libvgmstream.vcxproj.filters | 3 + src/meta/adm3.c | 152 +++++++++++++++++++++++++++++++ src/meta/meta.h | 2 + src/vgmstream.c | 1 + src/vgmstream.h | 1 + 7 files changed, 161 insertions(+) create mode 100644 src/meta/adm3.c diff --git a/src/formats.c b/src/formats.c index e8b501e6..f96d69c2 100644 --- a/src/formats.c +++ b/src/formats.c @@ -1393,6 +1393,7 @@ static const meta_info meta_info_list[] = { {meta_SSPF, "Konami SSPF header"}, {meta_S3V, "Konami S3V header"}, {meta_ESF, "Eurocom ESF header"}, + {meta_ADM3, "Crankcase ADM3 header"}, }; void get_vgmstream_coding_description(VGMSTREAM* vgmstream, char* out, size_t out_size) { diff --git a/src/libvgmstream.vcxproj b/src/libvgmstream.vcxproj index 08731c78..9fe1a518 100644 --- a/src/libvgmstream.vcxproj +++ b/src/libvgmstream.vcxproj @@ -310,6 +310,7 @@ + diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters index 49bab637..f3c95f61 100644 --- a/src/libvgmstream.vcxproj.filters +++ b/src/libvgmstream.vcxproj.filters @@ -415,6 +415,9 @@ meta\Source Files + + meta\Source Files + meta\Source Files diff --git a/src/meta/adm3.c b/src/meta/adm3.c new file mode 100644 index 00000000..f38ed06b --- /dev/null +++ b/src/meta/adm3.c @@ -0,0 +1,152 @@ +#include "meta.h" +#include "../coding/coding.h" + + +typedef struct { + int total_subsongs; + int target_subsong; + + uint32_t stream_offset; + uint32_t stream_size; + + int loop_flag; + int sample_rate; + int channels; + int32_t num_samples; +} adm3_header_t; + +static int parse_adm3(adm3_header_t* adm3, STREAMFILE* sf); + + +/* ADM3 - Crankcase Audio REV plugin file [Cyberpunk 2077 (PC), MotoGP 21 (PC)] */ +VGMSTREAM* init_vgmstream_adm3(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + adm3_header_t adm3 = {0}; + + + /* checks */ + if (!is_id32be(0x00,sf, "ADM3")) + goto fail; + if (!check_extensions(sf, "wem")) + goto fail; + + adm3.target_subsong = sf->stream_index; + if (adm3.target_subsong == 0) adm3.target_subsong = 1; + + /* ADM3 are files used with the Wwise Crankaudio plugin, that simulate engine noises with + * base internal samples and some internal RPM config (probably). Actual file seems to + * define some combo of samples, this only plays those separate samples. + * Decoder is basically Apple's IMA (internally just "ADPCMDecoder") but transforms to float + * each sample during decode by multiplying by 0.000030518509 */ + + if (!parse_adm3(&adm3, sf)) + goto fail; + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(adm3.channels, adm3.loop_flag); + if (!vgmstream) goto fail; + + vgmstream->meta_type = meta_ADM3; + vgmstream->sample_rate = adm3.sample_rate; + vgmstream->num_samples = adm3.num_samples; /* slightly lower than bytes-to-samples */ + vgmstream->num_streams = adm3.total_subsongs; + vgmstream->stream_size = adm3.stream_size; + + vgmstream->coding_type = coding_APPLE_IMA4; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x22; + + if (!vgmstream_open_stream(vgmstream, sf, adm3.stream_offset)) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} + + +static int parse_type(adm3_header_t* adm3, STREAMFILE* sf, uint32_t offset) { + + if (is_id32be(offset, sf, "RMP1")) { + offset = read_u32le(offset + 0x1c, sf); + if (!parse_type(adm3, sf, offset)) + goto fail; + /* 0x24: offset to GRN1 */ + } + else if (is_id32be(offset, sf, "SMB1")) { + uint32_t table_count = read_u32le(offset + 0x10, sf); + uint32_t table_offset = read_u32le(offset + 0x18, sf); + int i; + + for (i = 0; i < table_count; i++) { + uint32_t smp2_unk = read_u32le(table_offset + i * 0x08 + 0x00, sf); + uint32_t smp2_offset = read_u32le(table_offset + i * 0x08 + 0x04, sf); + + if (smp2_unk != 1) + goto fail; + + if (!parse_type(adm3, sf, smp2_offset)) /* SMP2 */ + goto fail; + } + } + else if (is_id32be(offset, sf, "SMP2")) { + adm3->total_subsongs++; + + if (adm3->target_subsong == adm3->total_subsongs) { + /* 0x04 always 0 */ + /* 0x08 always 0x00040000 */ + adm3->channels = read_u32le(offset + 0x0c, sf); + /* 0x10 float pitch? */ + /* 0x14 int pitch? */ + /* 0x18 0x0001? */ + /* 0x1a 0x0030? (header size?) */ + adm3->sample_rate = read_s32le(offset + 0x1c, sf); + adm3->num_samples = read_s32le(offset + 0x20, sf); + adm3->stream_size = read_u32le(offset + 0x24, sf); + /* 0x28 1? */ + adm3->stream_offset = read_u32le(offset + 0x2c, sf); + } + } + else { + VGM_LOG("ADM3: unknown at %x\n", offset); + goto fail; + } + + return 1; +fail: + return 0; +} + +static int parse_adm3(adm3_header_t* adm3, STREAMFILE* sf) { + uint32_t offset; + + /* 0x04: null */ + /* 0x08: version? */ + /* 0x0c: header size */ + /* 0x10: data start */ + /* rest unknown, looks mostly the same between files */ + + /* higher ramp, N samples from low to high */ + offset = read_u32le(0x0FC, sf); + if (!parse_type(adm3, sf, offset)) goto fail; /* RMP1 */ + if (read_u32le(0x100, sf) != 1) goto fail; + + /* lower ramp, also N samples */ + offset = read_u32le(0x104, sf); + if (!parse_type(adm3, sf, offset)) goto fail; /* RMP1 */ + if (read_u32le(0x108, sf) != 1) goto fail; + + /* idle engine */ + offset = read_u32le(0x10c, sf); + if (!parse_type(adm3, sf, offset)) goto fail; /* SMP2 */ + if (read_u32le(0x110, sf) != 1) goto fail; + + if (adm3->target_subsong < 0 || adm3->target_subsong > adm3->total_subsongs || adm3->total_subsongs < 1) + goto fail; + + return 1; +fail: + return 0; +} diff --git a/src/meta/meta.h b/src/meta/meta.h index ccfbaa68..17402a22 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -984,4 +984,6 @@ VGMSTREAM* init_vgmstream_s3v(STREAMFILE* sf); VGMSTREAM* init_vgmstream_esf(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_adm3(STREAMFILE* sf); + #endif /*_META_H*/ diff --git a/src/vgmstream.c b/src/vgmstream.c index b65f36e8..9969f904 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -523,6 +523,7 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = { init_vgmstream_opus_rsnd, init_vgmstream_s3v, init_vgmstream_esf, + init_vgmstream_adm3, /* lower priority metas (no clean header identity, somewhat ambiguous, or need extension/companion file to identify) */ init_vgmstream_mpeg, diff --git a/src/vgmstream.h b/src/vgmstream.h index c5501565..45100628 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -757,6 +757,7 @@ typedef enum { meta_SSPF, meta_S3V, meta_ESF, + meta_ADM3, } meta_t; From 2c9b8e614b639e6192a33d3a6e490b93e0221c17 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 1 May 2022 18:10:22 +0200 Subject: [PATCH 05/10] Add .audio_data [Lego SW: The Skywalker Saga (PC)] --- src/coding/ima_decoder.c | 16 +++--- src/decode.c | 11 +++- src/formats.c | 4 ++ src/layout/blocked.c | 3 + src/layout/blocked_tt_ad.c | 31 +++++++++++ src/layout/layout.h | 1 + src/libvgmstream.vcxproj | 2 + src/libvgmstream.vcxproj.filters | 6 ++ src/meta/meta.h | 2 + src/meta/tt_ad.c | 94 ++++++++++++++++++++++++++++++++ src/render.c | 1 + src/vgmstream.c | 8 ++- src/vgmstream.h | 3 + 13 files changed, 170 insertions(+), 12 deletions(-) create mode 100644 src/layout/blocked_tt_ad.c create mode 100644 src/meta/tt_ad.c diff --git a/src/coding/ima_decoder.c b/src/coding/ima_decoder.c index a6ec41ac..68e6d3f6 100644 --- a/src/coding/ima_decoder.c +++ b/src/coding/ima_decoder.c @@ -563,21 +563,23 @@ void decode_blitz_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channels /* IMA with custom frame sizes, header and nibble layout. Outputs an odd number of samples per frame, * so to simplify calcs this decodes full frames, thus hist doesn't need to be mantained. * Officially defined in "Microsoft Multimedia Standards Update" doc (RIFFNEW.pdf). */ -void decode_ms_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) { +void decode_ms_ima(VGMSTREAM* vgmstream, VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) { int i, samples_read = 0, samples_done = 0, max_samples; int32_t hist1;// = stream->adpcm_history1_32; int step_index;// = stream->adpcm_step_index; + int frame_channels = vgmstream->codec_config ? 1 : vgmstream->channels; /* mono or mch modes */ + int frame_channel = vgmstream->codec_config ? 0 : channel; /* internal interleave (configurable size), mixed channels */ - int block_samples = ((vgmstream->interleave_block_size - 0x04*vgmstream->channels) * 2 / vgmstream->channels) + 1; + int block_samples = ((vgmstream->frame_size - 0x04*frame_channels) * 2 / frame_channels) + 1; first_sample = first_sample % block_samples; /* normal header (hist+step+reserved), per channel */ { //if (first_sample == 0) { - off_t header_offset = stream->offset + 0x04*channel; + off_t header_offset = stream->offset + 0x04*frame_channel; - hist1 = read_16bitLE(header_offset+0x00,stream->streamfile); - step_index = read_8bit(header_offset+0x02,stream->streamfile); /* 0x03: reserved */ + hist1 = read_s16le(header_offset+0x00,stream->streamfile); + step_index = read_u8(header_offset+0x02,stream->streamfile); /* 0x03: reserved */ if (step_index < 0) step_index = 0; if (step_index > 88) step_index = 88; @@ -595,7 +597,7 @@ void decode_ms_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * /* decode nibbles (layout: alternates 4 bytes/4*2 nibbles per channel) */ for (i = 0; i < max_samples; i++) { - off_t byte_offset = stream->offset + 0x04*vgmstream->channels + 0x04*channel + 0x04*vgmstream->channels*(i/8) + (i%8)/2; + off_t byte_offset = stream->offset + 0x04*frame_channels + 0x04*frame_channel + 0x04*frame_channels*(i/8) + (i%8)/2; int nibble_shift = (i&1?4:0); /* low nibble first */ std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); /* original expand */ @@ -609,7 +611,7 @@ void decode_ms_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * /* internal interleave: increment offset on complete frame */ if (first_sample + samples_done == block_samples) { - stream->offset += vgmstream->interleave_block_size; + stream->offset += vgmstream->frame_size; } //stream->adpcm_history1_32 = hist1; diff --git a/src/decode.c b/src/decode.c index 1549e78e..0e82f468 100644 --- a/src/decode.c +++ b/src/decode.c @@ -428,7 +428,9 @@ int get_vgmstream_samples_per_frame(VGMSTREAM* vgmstream) { return 64; case coding_MS_IMA: case coding_REF_IMA: - return ((vgmstream->interleave_block_size - 0x04*vgmstream->channels) * 2 / vgmstream->channels) + 1; + return ((vgmstream->interleave_block_size - 0x04*vgmstream->channels) * 2 / vgmstream->channels) + 1;/* +1 from header sample */ + case coding_MS_IMA_mono: + return ((vgmstream->frame_size - 0x04) * 2) + 1; /* +1 from header sample */ case coding_RAD_IMA: return (vgmstream->interleave_block_size - 0x04*vgmstream->channels) * 2 / vgmstream->channels; case coding_NDS_IMA: @@ -628,12 +630,14 @@ int get_vgmstream_frame_size(VGMSTREAM* vgmstream) { case coding_OKI4S: case coding_MTF_IMA: return 0x01; - case coding_MS_IMA: case coding_RAD_IMA: case coding_NDS_IMA: case coding_DAT4_IMA: case coding_REF_IMA: return vgmstream->interleave_block_size; + case coding_MS_IMA: + case coding_MS_IMA_mono: + return vgmstream->frame_size; case coding_AWC_IMA: return 0x800; case coding_RAD_IMA_mono: @@ -931,6 +935,9 @@ void decode_vgmstream(VGMSTREAM* vgmstream, int samples_written, int samples_to_ } break; case coding_MS_IMA: + case coding_MS_IMA_mono: + //TODO: improve + vgmstream->codec_config = (vgmstream->coding_type == coding_MS_IMA_mono) || vgmstream->channels == 1; /* mono mode */ for (ch = 0; ch < vgmstream->channels; ch++) { decode_ms_ima(vgmstream,&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch); diff --git a/src/formats.c b/src/formats.c index f96d69c2..d08c0749 100644 --- a/src/formats.c +++ b/src/formats.c @@ -82,6 +82,7 @@ static const char* extension_list[] = { "atx", "aud", "audio", //txth/reserved [Grimm Echoes (Android)] + "audio_data", "aus", "awa", //txth/reserved [Missing Parts Side A (PS2)] "awb", @@ -781,6 +782,7 @@ static const coding_info coding_info_list[] = { {coding_MTF_IMA, "MT Framework 4-bit IMA ADPCM"}, {coding_MS_IMA, "Microsoft 4-bit IMA ADPCM"}, + {coding_MS_IMA_mono, "Microsoft 4-bit IMA ADPCM (mono/interleave)"}, {coding_XBOX_IMA, "XBOX 4-bit IMA ADPCM"}, {coding_XBOX_IMA_mch, "XBOX 4-bit IMA ADPCM (multichannel)"}, {coding_XBOX_IMA_int, "XBOX 4-bit IMA ADPCM (mono/interleave)"}, @@ -928,6 +930,7 @@ static const layout_info layout_info_list[] = { {layout_blocked_vs_square, "blocked (Square VS)"}, {layout_blocked_vid1, "blocked (VID1)"}, {layout_blocked_ubi_sce, "blocked (Ubi SCE)"}, + {layout_blocked_tt_ad, "blocked (TT AD)"}, }; static const meta_info meta_info_list[] = { @@ -1394,6 +1397,7 @@ static const meta_info meta_info_list[] = { {meta_S3V, "Konami S3V header"}, {meta_ESF, "Eurocom ESF header"}, {meta_ADM3, "Crankcase ADM3 header"}, + {meta_TT_AD, "Traveller's Tales AUDIO_DATA header"}, }; void get_vgmstream_coding_description(VGMSTREAM* vgmstream, char* out, size_t out_size) { diff --git a/src/layout/blocked.c b/src/layout/blocked.c index ef574958..dff0e496 100644 --- a/src/layout/blocked.c +++ b/src/layout/blocked.c @@ -213,6 +213,9 @@ void block_update(off_t block_offset, VGMSTREAM* vgmstream) { case layout_blocked_ubi_sce: block_update_ubi_sce(block_offset,vgmstream); break; + case layout_blocked_tt_ad: + block_update_tt_ad(block_offset,vgmstream); + break; default: /* not a blocked layout */ break; } diff --git a/src/layout/blocked_tt_ad.c b/src/layout/blocked_tt_ad.c new file mode 100644 index 00000000..f5f1be8f --- /dev/null +++ b/src/layout/blocked_tt_ad.c @@ -0,0 +1,31 @@ +#include "layout.h" + +/* Traveller's Tales blocks (.AUDIO_DATA) */ +void block_update_tt_ad(off_t block_offset, VGMSTREAM* vgmstream) { + STREAMFILE* sf = vgmstream->ch[0].streamfile; + uint32_t header_id, block_size, header_size; + int i; + + header_size = 0x00; + block_size = vgmstream->frame_size; + + //TODO could be optimized? + /* first chunk and last frame has an extra header: + * 0x00: id + * 0x04: 0 in FRST, left samples in LAST, others not seen (found in exe) */ + header_id = read_u32be(block_offset, sf); + if (header_id == get_id32be("FRST") || header_id == get_id32be("LAST") || + header_id == get_id32be("LSRT") || header_id == get_id32be("LEND")) { + header_size = 0x08; + } + VGM_ASSERT(header_id == get_id32be("LSRT") || header_id == get_id32be("LEND"), "TT-AD: loop found\n"); + + vgmstream->current_block_offset = block_offset; + vgmstream->current_block_size = block_size /* * vgmstream->channels*/; + vgmstream->next_block_offset = block_offset + block_size * vgmstream->channels + header_size; + + /* MS-IMA = same offset per channel */ + for (i = 0; i < vgmstream->channels; i++) { + vgmstream->ch[i].offset = vgmstream->current_block_offset + header_size + block_size * i; + } +} diff --git a/src/layout/layout.h b/src/layout/layout.h index 79dc63b5..7accda7e 100644 --- a/src/layout/layout.h +++ b/src/layout/layout.h @@ -49,6 +49,7 @@ void block_update_xa_aiff(off_t block_offset, VGMSTREAM* vgmstream); void block_update_vs_square(off_t block_offset, VGMSTREAM* vgmstream); void block_update_vid1(off_t block_offset, VGMSTREAM* vgmstream); void block_update_ubi_sce(off_t block_offset, VGMSTREAM* vgmstream); +void block_update_tt_ad(off_t block_offset, VGMSTREAM* vgmstream); /* other layouts */ void render_vgmstream_interleave(sample_t* buffer, int32_t sample_count, VGMSTREAM* vgmstream); diff --git a/src/libvgmstream.vcxproj b/src/libvgmstream.vcxproj index 9fe1a518..880b3312 100644 --- a/src/libvgmstream.vcxproj +++ b/src/libvgmstream.vcxproj @@ -564,6 +564,7 @@ + @@ -722,6 +723,7 @@ + diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters index f3c95f61..a9123765 100644 --- a/src/libvgmstream.vcxproj.filters +++ b/src/libvgmstream.vcxproj.filters @@ -1159,6 +1159,9 @@ meta\Source Files + + meta\Source Files + meta\Source Files @@ -1606,6 +1609,9 @@ layout\Source Files + + layout\Source Files + layout\Source Files diff --git a/src/meta/meta.h b/src/meta/meta.h index 17402a22..4aff0a00 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -986,4 +986,6 @@ VGMSTREAM* init_vgmstream_esf(STREAMFILE* sf); VGMSTREAM* init_vgmstream_adm3(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_tt_ad(STREAMFILE* sf); + #endif /*_META_H*/ diff --git a/src/meta/tt_ad.c b/src/meta/tt_ad.c new file mode 100644 index 00000000..5bfffa50 --- /dev/null +++ b/src/meta/tt_ad.c @@ -0,0 +1,94 @@ +#include "meta.h" +#include "../coding/coding.h" + +/* .AUDIO_DATA - Traveller's Tales "NTT" engine audio format [Lego Star Wars: The Skywalker Saga (PC/Switch)] */ +VGMSTREAM* init_vgmstream_tt_ad(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + uint32_t offset, stream_offset, stream_size; + int loop_flag, channels, sample_rate, codec, frame_size = 0; + int32_t num_samples; + + + /* checks */ + if (!is_id32be(0x00,sf, "FMT ")) + goto fail; + + /* actual extension */ + if (!check_extensions(sf, "audio_data")) + goto fail; + + offset = 0x08; + /* 0x00: null */ + codec = read_u16le(offset + 0x02,sf); + sample_rate = read_s32le(offset + 0x04,sf); + num_samples = read_s32le(offset + 0x08,sf); + channels = read_u8(offset + 0x0c,sf); + /* 0x0d: bps (16=IMA, 32=Ogg) */ + /* 0x10: + Ogg = some size? + IMA = frame size + flag? */ + if (codec == 0x0a) + frame_size = read_u16le(offset + 0x10,sf); + + + loop_flag = 0; /* music just repeats? */ + + offset += read_u32le(0x04, sf); + + /* Ogg seek table*/ + if (is_id32be(offset, sf, "SEEK")) { + offset += 0x08 + read_u32le(offset + 0x04, sf); + } + + /* found with some IMA */ + if (is_id32be(offset, sf, "RMS ")) { + offset += 0x08 + read_u32le(offset + 0x04, sf); + } + + if (!is_id32be(offset, sf, "DATA")) + goto fail; + + stream_offset = offset + 0x08; + stream_size = read_u32le(offset + 0x04, sf); + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channels, loop_flag); + if (!vgmstream) goto fail; + + vgmstream->meta_type = meta_TT_AD; + vgmstream->sample_rate = sample_rate; + vgmstream->num_samples = num_samples; + + switch(codec) { +#ifdef VGM_USE_VORBIS + case 0x01: { + vgmstream->codec_data = init_ogg_vorbis(sf, stream_offset, stream_size, NULL); + if (!vgmstream->codec_data) goto fail; + vgmstream->coding_type = coding_OGG_VORBIS; + vgmstream->layout_type = layout_none; + + break; + } +#endif + + case 0x0a: + vgmstream->coding_type = coding_MS_IMA_mono; + vgmstream->layout_type = layout_blocked_tt_ad; + vgmstream->frame_size = frame_size; + vgmstream->interleave_block_size = frame_size; + break; + + default: + vgm_logi("FMT: unsupported codec 0x%x\n", codec); + goto fail; + } + + if (!vgmstream_open_stream(vgmstream, sf, stream_offset)) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} diff --git a/src/render.c b/src/render.c index 5e5243a2..6233ec84 100644 --- a/src/render.c +++ b/src/render.c @@ -304,6 +304,7 @@ int render_layout(sample_t* buf, int32_t sample_count, VGMSTREAM* vgmstream) { case layout_blocked_vs_square: case layout_blocked_vid1: case layout_blocked_ubi_sce: + case layout_blocked_tt_ad: render_vgmstream_blocked(buf, sample_count, vgmstream); break; case layout_segmented: diff --git a/src/vgmstream.c b/src/vgmstream.c index 9969f904..f3ad67ff 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -524,6 +524,7 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = { init_vgmstream_s3v, init_vgmstream_esf, init_vgmstream_adm3, + init_vgmstream_tt_ad, /* lower priority metas (no clean header identity, somewhat ambiguous, or need extension/companion file to identify) */ init_vgmstream_mpeg, @@ -1161,9 +1162,10 @@ int vgmstream_open_stream_bf(VGMSTREAM* vgmstream, STREAMFILE* sf, off_t start_o goto fail; } - if ((vgmstream->coding_type == coding_MSADPCM || - vgmstream->coding_type == coding_MSADPCM_ck || - vgmstream->coding_type == coding_MSADPCM_int) && + if ((vgmstream->coding_type == coding_MSADPCM || vgmstream->coding_type == coding_MSADPCM_ck || + vgmstream->coding_type == coding_MSADPCM_int || + vgmstream->coding_type == coding_MS_IMA || vgmstream->coding_type == coding_MS_IMA_mono + ) && vgmstream->frame_size == 0) { vgmstream->frame_size = vgmstream->interleave_block_size; } diff --git a/src/vgmstream.h b/src/vgmstream.h index 45100628..86e680de 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -114,6 +114,7 @@ typedef enum { coding_BLITZ_IMA, /* Blitz Games 4-bit IMA ADPCM */ coding_MS_IMA, /* Microsoft IMA ADPCM */ + coding_MS_IMA_mono, /* Microsoft IMA ADPCM (mono/interleave) */ coding_XBOX_IMA, /* XBOX IMA ADPCM */ coding_XBOX_IMA_mch, /* XBOX IMA ADPCM (multichannel) */ coding_XBOX_IMA_int, /* XBOX IMA ADPCM (mono/interleave) */ @@ -277,6 +278,7 @@ typedef enum { layout_blocked_vs_square, layout_blocked_vid1, layout_blocked_ubi_sce, + layout_blocked_tt_ad, /* otherwise odd */ layout_segmented, /* song divided in segments (song sections) */ @@ -758,6 +760,7 @@ typedef enum { meta_S3V, meta_ESF, meta_ADM3, + meta_TT_AD, } meta_t; From 38773bdab7aaf2373f68c8febacd021a5d6d13fd Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 1 May 2022 18:10:38 +0200 Subject: [PATCH 06/10] Fix bitrate in some cases --- src/info.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/info.c b/src/info.c index 6d711ed9..d9112170 100644 --- a/src/info.c +++ b/src/info.c @@ -358,7 +358,13 @@ static int get_vgmstream_file_bitrate_main(VGMSTREAM* vgmstream, bitrate_info_t* * segments use only a few samples from a full file (like Wwise transitions), bitrates * become a bit high since its hard to detect only part of the file is needed. */ - if (vgmstream->layout_type == layout_segmented) { + if (vgmstream->stream_size != 0) { + /* format may report full size for custom layouts that otherwise get odd values */ + bitrate += get_vgmstream_file_bitrate_from_size(vgmstream->stream_size, vgmstream->sample_rate, vgmstream->num_samples); + if (p_uniques) + (*p_uniques)++; + } + else if (vgmstream->layout_type == layout_segmented) { int uniques = 0; segmented_layout_data *data = (segmented_layout_data *) vgmstream->layout_data; for (i = 0; i < data->segment_count; i++) { @@ -400,20 +406,20 @@ static int get_vgmstream_file_bitrate_main(VGMSTREAM* vgmstream, bitrate_info_t* } if (is_unique) { - size_t stream_size; - + size_t file_bitrate; + if (br->count >= br->count_max) goto fail; if (vgmstream->stream_size) { /* stream_size applies to both channels but should add once and detect repeats (for current subsong) */ - stream_size = get_vgmstream_file_bitrate_from_size(vgmstream->stream_size, vgmstream->sample_rate, vgmstream->num_samples); + file_bitrate = get_vgmstream_file_bitrate_from_size(vgmstream->stream_size, vgmstream->sample_rate, vgmstream->num_samples); } else { - stream_size = get_vgmstream_file_bitrate_from_streamfile(sf_cur, vgmstream->sample_rate, vgmstream->num_samples); + file_bitrate = get_vgmstream_file_bitrate_from_streamfile(sf_cur, vgmstream->sample_rate, vgmstream->num_samples); } /* possible in cases like using silence codec */ - if (!stream_size) + if (!file_bitrate) break; br->hash[br->count] = hash_cur; @@ -423,7 +429,7 @@ static int get_vgmstream_file_bitrate_main(VGMSTREAM* vgmstream, bitrate_info_t* if (p_uniques) (*p_uniques)++; - bitrate += stream_size; + bitrate += file_bitrate; break; } From 1849395b8e6e4bb2c776be439dbf110cada11cd3 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 1 May 2022 18:56:52 +0200 Subject: [PATCH 07/10] Improve MPEG parser --- src/coding/coding.h | 1 + src/coding/mpeg_custom_utils.c | 91 ++++++++++++++++++++-------------- src/meta/mpeg.c | 21 +++++++- 3 files changed, 73 insertions(+), 40 deletions(-) diff --git a/src/coding/coding.h b/src/coding/coding.h index 1ef00f5b..bd2c800e 100644 --- a/src/coding/coding.h +++ b/src/coding/coding.h @@ -491,6 +491,7 @@ void free_mpeg(mpeg_codec_data* data); int mpeg_get_sample_rate(mpeg_codec_data* data); long mpeg_bytes_to_samples(long bytes, const mpeg_codec_data* data); +uint32_t mpeg_get_tag_size(STREAMFILE* sf, uint32_t offset, uint32_t header); int mpeg_get_frame_info(STREAMFILE* sf, off_t offset, mpeg_frame_info* info); #endif diff --git a/src/coding/mpeg_custom_utils.c b/src/coding/mpeg_custom_utils.c index 4a91fa66..b86c9c38 100644 --- a/src/coding/mpeg_custom_utils.c +++ b/src/coding/mpeg_custom_utils.c @@ -340,6 +340,37 @@ int mpeg_get_frame_info(STREAMFILE* sf, off_t offset, mpeg_frame_info* info) { return mpeg_get_frame_info_h(header, info); } + +uint32_t mpeg_get_tag_size(STREAMFILE* sf, uint32_t offset, uint32_t header) { + if (!header) + header = read_u32be(offset+0x00, sf); + + /* skip ID3v2 */ + if ((header & 0xFFFFFF00) == get_id32be("ID3\0")) { + size_t frame_size = 0; + uint8_t flags = read_u8(offset+0x05, sf); + /* this is how it's officially read :/ */ + frame_size += read_u8(offset+0x06, sf) << 21; + frame_size += read_u8(offset+0x07, sf) << 14; + frame_size += read_u8(offset+0x08, sf) << 7; + frame_size += read_u8(offset+0x09, sf) << 0; + frame_size += 0x0a; + if (flags & 0x10) /* footer? */ + frame_size += 0x0a; + + return frame_size; + + } + + /* skip ID3v1 */ + if ((header & 0xFFFFFF00) == get_id32be("TAG\0")) { + ;VGM_LOG("MPEG: ID3v1 at %x\n", offset); + return 0x80; + } + + return 0; +} + size_t mpeg_get_samples(STREAMFILE* sf, off_t start_offset, size_t bytes) { off_t offset = start_offset; off_t max_offset = start_offset + bytes; @@ -355,32 +386,13 @@ size_t mpeg_get_samples(STREAMFILE* sf, off_t start_offset, size_t bytes) { /* MPEG may use VBR so must read all frames */ while (offset < max_offset) { uint32_t header = read_u32be(offset+0x00, sf); - - /* skip ID3v2 */ - if ((header & 0xFFFFFF00) == 0x49443300) { /* "ID3\0" */ - size_t frame_size = 0; - uint8_t flags = read_u8(offset+0x05, sf); - /* this is how it's officially read :/ */ - frame_size += read_u8(offset+0x06, sf) << 21; - frame_size += read_u8(offset+0x07, sf) << 14; - frame_size += read_u8(offset+0x08, sf) << 7; - frame_size += read_u8(offset+0x09, sf) << 0; - frame_size += 0x0a; - if (flags & 0x10) /* footer? */ - frame_size += 0x0a; - - offset += frame_size; + size_t tag_size = mpeg_get_tag_size(sf, offset, header); + if (tag_size) { + offset += tag_size; continue; } - /* skip ID3v1 */ - if ((header & 0xFFFFFF00) == 0x54414700) { /* "TAG\0" */ - ;VGM_LOG("MPEG: ID3v1 at %lx\n", offset); - offset += 0x80; - continue; - } - - /* regular frame */ + /* regular frame (assumed) */ if (!mpeg_get_frame_info_h(header, &info)) { VGM_LOG("MPEG: unknown frame at %lx\n", offset); break; @@ -407,28 +419,31 @@ size_t mpeg_get_samples(STREAMFILE* sf, off_t start_offset, size_t bytes) { } /* other flags indicate seek table and stuff */ - /* vendor specific */ - if (info.frame_size > xing_offset + 0x78 + 0x24 && - read_u32be(offset + xing_offset + 0x78, sf) == 0x4C414D45) { /* "LAME" */ - if (info.layer == 3) { - uint32_t delays = read_u32be(offset + xing_offset + 0x8C, sf); - encoder_delay = ((delays >> 12) & 0xFFF); - encoder_padding = ((delays >> 0) & 0xFFF); + ;VGM_LOG("MPEG: found Xing header\n"); - encoder_delay += (528 + 1); /* implicit MDCT decoder delay (seen in LAME source) */ - if (encoder_padding > 528 + 1) - encoder_padding -= (528 + 1); - } - else { - encoder_delay = 240 + 1; + /* vendor specific */ + if (info.frame_size > xing_offset + 0x78 + 0x24) { + uint32_t sub_id = read_u32be(offset + xing_offset + 0x78, sf); + if (sub_id == get_id32be("LAME") || /* LAME */ + sub_id == get_id32be("Lavc")) { /* FFmpeg */ + if (info.layer == 3) { + uint32_t delays = read_u32be(offset + xing_offset + 0x8C, sf); + encoder_delay = ((delays >> 12) & 0xFFF); + encoder_padding = ((delays >> 0) & 0xFFF); + + encoder_delay += (528 + 1); /* implicit MDCT decoder delay (seen in LAME source) */ + if (encoder_padding > 528 + 1) + encoder_padding -= (528 + 1); + } + else { + encoder_delay = 240 + 1; + } } /* replay gain and stuff */ } /* there is also "iTunes" vendor with no apparent extra info, iTunes delays are in "iTunSMPB" ID3 tag */ - - ;VGM_LOG("MPEG: found Xing header\n"); break; /* we got samples */ } } diff --git a/src/meta/mpeg.c b/src/meta/mpeg.c index cbe454b9..b3fad20a 100644 --- a/src/meta/mpeg.c +++ b/src/meta/mpeg.c @@ -2,16 +2,33 @@ #include "../coding/coding.h" -/* MPEG - standard MP1/2/3 audio MP3 */ +/* MPEG - standard MP1/2/3 audio */ VGMSTREAM* init_vgmstream_mpeg(STREAMFILE* sf) { #ifdef VGM_USE_MPEG VGMSTREAM* vgmstream = NULL; + uint32_t start_offset; int loop_flag = 0; mpeg_frame_info info = {0}; + uint32_t header_id; /* checks */ - if (!mpeg_get_frame_info(sf, 0x00, &info)) + header_id = read_u32be(0x00, sf); + if ((header_id & 0xFFF00000) != 0xFFF00000 && + (header_id & 0xFFFFFF00) != get_id32be("ID3\0") && + (header_id & 0xFFFFFF00) != get_id32be("TAG\0")) + goto fail; + + //TODO: may try init_mpeg as-is, already skips tags + start_offset = 0x00; + while (start_offset < get_streamfile_size(sf)) { + uint32_t tag_size = mpeg_get_tag_size(sf, start_offset, 0); + if (tag_size == 0) + break; + start_offset += tag_size; + } + + if (!mpeg_get_frame_info(sf, start_offset, &info)) goto fail; /* .mp3/mp2: standard (is .mp1 ever used in games?) From 61e82459b2e1eca87781fb7638ee1b75b7bb1c0e Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 1 May 2022 18:57:22 +0200 Subject: [PATCH 08/10] Improve Tiger .com validations and lower priority --- src/meta/tgc.c | 22 +++++++++++++++++----- src/vgmstream.c | 2 +- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/meta/tgc.c b/src/meta/tgc.c index a865309e..806f8e65 100644 --- a/src/meta/tgc.c +++ b/src/meta/tgc.c @@ -2,24 +2,36 @@ #include "../coding/coding.h" /* Tiger Game.com ADPCM file */ -VGMSTREAM * init_vgmstream_tgc(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; +VGMSTREAM* init_vgmstream_tgc(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + uint16_t size; + off_t start_offset; + /* checks */ - if (!check_extensions(streamFile, "4")) + if (read_u8(0x00, sf) != 0) goto fail; + if (!check_extensions(sf, "4")) + goto fail; + + size = read_u16be(0x01, sf); + if (size != get_streamfile_size(sf)) + goto fail; + start_offset = 0x03; + + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(1, 0); if (!vgmstream) goto fail; vgmstream->sample_rate = 8000; - vgmstream->num_samples = ((uint16_t)read_16bitBE(1, streamFile) - 3) * 2; + vgmstream->num_samples = (size - 0x03) * 2; vgmstream->meta_type = meta_TGC; vgmstream->layout_type = layout_none; vgmstream->coding_type = coding_TGC; - if (!vgmstream_open_stream(vgmstream, streamFile, 3)) + if (!vgmstream_open_stream(vgmstream, sf, start_offset)) goto fail; return vgmstream; diff --git a/src/vgmstream.c b/src/vgmstream.c index f3ad67ff..012adc5d 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -470,7 +470,6 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = { init_vgmstream_csb, init_vgmstream_fwse, init_vgmstream_fda, - init_vgmstream_tgc, init_vgmstream_kwb, init_vgmstream_lrmd, init_vgmstream_bkhd, @@ -538,6 +537,7 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = { init_vgmstream_seb, init_vgmstream_ps2_pnb, init_vgmstream_sli_ogg, + init_vgmstream_tgc, /* 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 */ From f4fe1482c9acef2956615ffbd735f4d1311018b6 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 1 May 2022 20:34:58 +0200 Subject: [PATCH 09/10] cleanup --- src/libvgmstream.vcxproj | 4 +-- src/libvgmstream.vcxproj.filters | 12 +++---- src/meta/aax.c | 62 ++++++++++++++++---------------- src/meta/acb.c | 2 +- src/meta/cpk.c | 7 ++-- src/meta/csb.c | 6 ++-- src/{meta => util}/cri_utf.c | 2 +- src/{meta => util}/cri_utf.h | 0 8 files changed, 49 insertions(+), 46 deletions(-) rename src/{meta => util}/cri_utf.c (99%) rename src/{meta => util}/cri_utf.h (100%) diff --git a/src/libvgmstream.vcxproj b/src/libvgmstream.vcxproj index 880b3312..8f6f33bd 100644 --- a/src/libvgmstream.vcxproj +++ b/src/libvgmstream.vcxproj @@ -110,7 +110,6 @@ - @@ -172,6 +171,7 @@ + @@ -340,7 +340,6 @@ - @@ -731,6 +730,7 @@ + diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters index a9123765..cad68294 100644 --- a/src/libvgmstream.vcxproj.filters +++ b/src/libvgmstream.vcxproj.filters @@ -95,9 +95,6 @@ meta\Header Files - - meta\Header Files - meta\Header Files @@ -314,6 +311,9 @@ Header Files + + meta\Header Files + Header Files @@ -490,9 +490,6 @@ meta\Source Files - - meta\Source Files - meta\Source Files @@ -1975,6 +1972,9 @@ Source Files + + meta\Source Files + Source Files diff --git a/src/meta/aax.c b/src/meta/aax.c index b8041009..3e509faa 100644 --- a/src/meta/aax.c +++ b/src/meta/aax.c @@ -1,31 +1,32 @@ #include "meta.h" #include "../layout/layout.h" #include "../coding/coding.h" -#include "cri_utf.h" +#include "../util/cri_utf.h" #define MAX_SEGMENTS 2 /* usually segment0=intro, segment1=loop/main */ /* AAX - segmented ADX [Bayonetta (PS3), Pandora's Tower (Wii), Catherine (X360), Binary Domain (PS3)] */ -VGMSTREAM * init_vgmstream_aax(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - int loop_flag = 0, channel_count = 0; +VGMSTREAM* init_vgmstream_aax(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + int loop_flag = 0, channels = 0; int32_t sample_count, loop_start_sample = 0, loop_end_sample = 0; - segmented_layout_data *data = NULL; + segmented_layout_data* data = NULL; int segment_count, loop_segment = 0, is_hca; off_t segment_offset[MAX_SEGMENTS]; size_t segment_size[MAX_SEGMENTS]; int i; - utf_context *utf = NULL; + utf_context* utf = NULL; /* checks */ + if (!is_id32be(0x00,sf, "@UTF")) + goto fail; + /* .aax: often with extension (with either HCA or AAX tables) * (extensionless): sometimes without [PES 2013 (PC)] */ - if (!check_extensions(streamFile, "aax,")) - goto fail; - if (read_32bitBE(0x00,streamFile) != 0x40555446) /* "@UTF" */ + if (!check_extensions(sf, "aax,")) goto fail; /* .aax contains a simple UTF table, each row being a segment pointing to a CRI audio format */ @@ -35,7 +36,7 @@ VGMSTREAM * init_vgmstream_aax(STREAMFILE *streamFile) { uint32_t table_offset = 0x00; - utf = utf_open(streamFile, table_offset, &rows, &name); + utf = utf_open(sf, table_offset, &rows, &name); if (!utf) goto fail; if (strcmp(name, "AAX") == 0) @@ -74,7 +75,7 @@ VGMSTREAM * init_vgmstream_aax(STREAMFILE *streamFile) { /* open each segment subfile */ for (i = 0; i < segment_count; i++) { - STREAMFILE* temp_sf = setup_subfile_streamfile(streamFile, segment_offset[i],segment_size[i], (is_hca ? "hca" : "adx")); + STREAMFILE* temp_sf = setup_subfile_streamfile(sf, segment_offset[i],segment_size[i], (is_hca ? "hca" : "adx")); if (!temp_sf) goto fail; data->segments[i] = is_hca ? @@ -105,11 +106,11 @@ VGMSTREAM * init_vgmstream_aax(STREAMFILE *streamFile) { } } - channel_count = data->output_channels; + channels = data->output_channels; /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); + vgmstream = allocate_vgmstream(channels,loop_flag); if (!vgmstream) goto fail; vgmstream->sample_rate = data->segments[0]->sample_rate; @@ -135,21 +136,22 @@ fail: /* CRI's UTF wrapper around DSP [Sonic Colors sfx (Wii), NiGHTS: Journey of Dreams sfx (Wii)] */ -VGMSTREAM * init_vgmstream_utf_dsp(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; +VGMSTREAM* init_vgmstream_utf_dsp(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; off_t start_offset; - uint8_t loop_flag = 0, channel_count; + uint8_t loop_flag = 0, channels; uint32_t sample_rate, num_samples, loop_start, loop_end, interleave; uint32_t data_offset, data_size, header_offset, header_size; - utf_context *utf = NULL; + utf_context* utf = NULL; /* checks */ + if (!is_id32be(0x00,sf, "@UTF")) + goto fail; + /* .aax: assumed * (extensionless): extracted names inside csb/cpk often don't have extensions */ - if (!check_extensions(streamFile, "aax,")) - goto fail; - if (read_32bitBE(0x00,streamFile) != 0x40555446) /* "@UTF" */ + if (!check_extensions(sf, "aax,")) goto fail; /* .aax contains a simple UTF table with one row and various columns being header info */ @@ -159,7 +161,7 @@ VGMSTREAM * init_vgmstream_utf_dsp(STREAMFILE *streamFile) { uint32_t table_offset = 0x00; - utf = utf_open(streamFile, table_offset, &rows, &name); + utf = utf_open(sf, table_offset, &rows, &name); if (!utf) goto fail; if (strcmp(name, "ADPCM_WII") != 0) @@ -172,7 +174,7 @@ VGMSTREAM * init_vgmstream_utf_dsp(STREAMFILE *streamFile) { goto fail; if (!utf_query_u32(utf, 0, "nsmpl", &num_samples)) goto fail; - if (!utf_query_u8(utf, 0, "nch", &channel_count)) + if (!utf_query_u8(utf, 0, "nch", &channels)) goto fail; if (!utf_query_u8(utf, 0, "lpflg", &loop_flag)) /* full loops */ goto fail; @@ -182,21 +184,21 @@ VGMSTREAM * init_vgmstream_utf_dsp(STREAMFILE *streamFile) { if (!utf_query_data(utf, 0, "header", &header_offset, &header_size)) goto fail; - if (channel_count < 1 || channel_count > 2) + if (channels < 1 || channels > 2) goto fail; - if (header_size != channel_count * 0x60) + if (header_size != channels * 0x60) goto fail; start_offset = data_offset; - interleave = (data_size+7) / 8 * 8 / channel_count; + interleave = (data_size+7) / 8 * 8 / channels; - loop_start = read_32bitBE(header_offset + 0x10, streamFile); - loop_end = read_32bitBE(header_offset + 0x14, streamFile); + loop_start = read_32bitBE(header_offset + 0x10, sf); + loop_end = read_32bitBE(header_offset + 0x14, sf); } /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count, loop_flag); + vgmstream = allocate_vgmstream(channels, loop_flag); if (!vgmstream) goto fail; vgmstream->sample_rate = sample_rate; @@ -209,9 +211,9 @@ VGMSTREAM * init_vgmstream_utf_dsp(STREAMFILE *streamFile) { vgmstream->interleave_block_size = interleave; vgmstream->meta_type = meta_UTF_DSP; - dsp_read_coefs_be(vgmstream, streamFile, header_offset+0x1c, 0x60); + dsp_read_coefs_be(vgmstream, sf, header_offset+0x1c, 0x60); - if (!vgmstream_open_stream(vgmstream, streamFile, start_offset)) + if (!vgmstream_open_stream(vgmstream, sf, start_offset)) goto fail; return vgmstream; diff --git a/src/meta/acb.c b/src/meta/acb.c index e51cc67a..84a4a115 100644 --- a/src/meta/acb.c +++ b/src/meta/acb.c @@ -1,6 +1,6 @@ #include "meta.h" #include "../coding/coding.h" -#include "cri_utf.h" +#include "../util/cri_utf.h" /* ACB (Atom Cue sheet Binary) - CRI container of memory audio, often together with a .awb wave bank */ diff --git a/src/meta/cpk.c b/src/meta/cpk.c index f42f2b73..1dd2ffaf 100644 --- a/src/meta/cpk.c +++ b/src/meta/cpk.c @@ -1,6 +1,6 @@ #include "meta.h" #include "../coding/coding.h" -#include "cri_utf.h" +#include "../util/cri_utf.h" typedef enum { HCA, CWAV, ADX } cpk_type_t; @@ -26,10 +26,11 @@ VGMSTREAM* init_vgmstream_cpk_memory(STREAMFILE* sf, STREAMFILE* sf_acb) { /* checks */ - if (!check_extensions(sf, "awb")) - goto fail; if (!is_id32be(0x00,sf, "CPK ")) goto fail; + if (!check_extensions(sf, "awb")) + goto fail; + if (!is_id32be(0x10,sf, "@UTF")) goto fail; /* 04: 0xFF? */ diff --git a/src/meta/csb.c b/src/meta/csb.c index 68be6d72..83211750 100644 --- a/src/meta/csb.c +++ b/src/meta/csb.c @@ -1,6 +1,6 @@ #include "meta.h" #include "../coding/coding.h" -#include "cri_utf.h" +#include "../util/cri_utf.h" /* CSB (Cue Sheet Binary?) - CRI container of memory audio, often together with a .cpk wave bank */ @@ -9,8 +9,8 @@ VGMSTREAM* init_vgmstream_csb(STREAMFILE* sf) { STREAMFILE* temp_sf = NULL; off_t subfile_offset; size_t subfile_size; - utf_context *utf = NULL; - utf_context *utf_sdl = NULL; + utf_context* utf = NULL; + utf_context* utf_sdl = NULL; int total_subsongs, target_subsong = sf->stream_index; uint8_t fmt = 0; const char* stream_name = NULL; diff --git a/src/meta/cri_utf.c b/src/util/cri_utf.c similarity index 99% rename from src/meta/cri_utf.c rename to src/util/cri_utf.c index a2919bec..e3174ca0 100644 --- a/src/meta/cri_utf.c +++ b/src/util/cri_utf.c @@ -1,5 +1,5 @@ #include "cri_utf.h" -#include "../util/log.h" +#include "log.h" #define UTF_MAX_SCHEMA_SIZE 0x8000 /* arbitrary max */ #define COLUMN_BITMASK_FLAG 0xf0 diff --git a/src/meta/cri_utf.h b/src/util/cri_utf.h similarity index 100% rename from src/meta/cri_utf.h rename to src/util/cri_utf.h From c16f305ef6d9787b09092c66729d81e198211ba4 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 1 May 2022 20:35:11 +0200 Subject: [PATCH 10/10] cleanup --- src/meta/riff.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/meta/riff.c b/src/meta/riff.c index 2220adaf..bd299934 100644 --- a/src/meta/riff.c +++ b/src/meta/riff.c @@ -654,8 +654,8 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) { read_u32be(start_offset+0x3c, sf) == 0xFFFFFFFF) goto fail; - ///* MSADPCM .ckd are parsed elsewhere, though they are valid so no big deal if parsed here (just that loops should be ignored) */ - if (!fmt.is_at9 && check_extensions(sf, "ckd")) + /* MSADPCM .ckd are parsed elsewhere, though they are valid so no big deal if parsed here (just that loops should be ignored) */ + if (fmt.codec == 0x0002 && check_extensions(sf, "ckd")) goto fail; /* ignore Gitaroo Man Live! (PSP) multi-RIFF (to allow chunked TXTH) */