diff --git a/src/coding/coding.h b/src/coding/coding.h index a656e326..672c9cc4 100644 --- a/src/coding/coding.h +++ b/src/coding/coding.h @@ -15,22 +15,25 @@ void decode_g721(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, void g72x_init_state(struct g72x_state *state_ptr); /* ima_decoder */ -void decode_nds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); -void decode_dat4_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); +void decode_standard_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo, int is_high_first); +void decode_3ds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); +void decode_snds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); +void decode_otns_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); +void decode_wv6_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); + +void decode_ms_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel); +void decode_ref_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel); + void decode_xbox_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); void decode_xbox_ima_mch(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); void decode_xbox_ima_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); -void decode_snds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); -void decode_standard_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo, int is_high_first); -void decode_3ds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); +void decode_nds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); +void decode_dat4_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_rad_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel); void decode_rad_ima_mono(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_apple_ima4(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); -void decode_ms_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel); -void decode_otns_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); void decode_fsb_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); void decode_wwise_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); -void decode_ref_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel); void decode_awc_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_ubi_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); size_t ima_bytes_to_samples(size_t bytes, int channels); diff --git a/src/coding/ima_decoder.c b/src/coding/ima_decoder.c index 9fc8902d..1db3f407 100644 --- a/src/coding/ima_decoder.c +++ b/src/coding/ima_decoder.c @@ -169,6 +169,25 @@ static void otns_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, if (*step_index > 88) *step_index=88; } +/* Fairly OddParents (PC) .WV6: minor variation, reverse engineered from the .exe */ +static void wv6_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, int nibble_shift, int32_t * hist1, int32_t * step_index) { + int sample_nibble, sample_decoded, step, delta; + + sample_nibble = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift)&0xf; + sample_decoded = *hist1; + step = ADPCMTable[*step_index]; + + delta = (sample_nibble & 0x7); + delta = ((delta * step) >> 3) + ((delta * step) >> 2); + if (sample_nibble & 8) delta = -delta; + sample_decoded += delta; + + *hist1 = clamp16(sample_decoded); + *step_index += IMA_IndexTable[sample_nibble]; + if (*step_index < 0) *step_index=0; + if (*step_index > 88) *step_index=88; +} + /* ************************************ */ /* DVI/IMA */ /* ************************************ */ @@ -269,6 +288,28 @@ void decode_otns_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * stream->adpcm_step_index = step_index; } +/* WV6 IMA, DVI IMA with custom nibble expand */ +void decode_wv6_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { + int i, sample_count; + int32_t hist1 = stream->adpcm_history1_32; + int step_index = stream->adpcm_step_index; + + //external interleave + + //no header + + for (i=first_sample,sample_count=0; ioffset + i/2; + int nibble_shift = (i&1?0:4); //high nibble first + + wv6_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); + outbuf[sample_count] = (short)(hist1); + } + + stream->adpcm_history1_32 = hist1; + stream->adpcm_step_index = step_index; +} + /* ************************************ */ /* MS-IMA */ /* ************************************ */ diff --git a/src/formats.c b/src/formats.c index 5f750a58..10f46b24 100644 --- a/src/formats.c +++ b/src/formats.c @@ -422,6 +422,7 @@ static const char* extension_list[] = { "wsd", "wsi", "wv2", //txth/reserved [Slave Zero (PC)] + "wv6", "wve", "wvs", @@ -528,6 +529,10 @@ static const coding_info coding_info_list[] = { {coding_DVI_IMA, "Intel DVI 4-bit IMA ADPCM"}, {coding_DVI_IMA_int, "Intel DVI 4-bit IMA ADPCM (mono/interleave)"}, {coding_3DS_IMA, "3DS IMA 4-bit ADPCM"}, + {coding_SNDS_IMA, "Heavy Iron .snds 4-bit IMA ADPCM"}, + {coding_OTNS_IMA, "Omikron: The Nomad Soul 4-bit IMA ADPCM"}, + {coding_WV6_IMA, "Gorilla Systems WV6 4-bit IMA ADPCM"}, + {coding_MS_IMA, "Microsoft 4-bit IMA ADPCM"}, {coding_XBOX_IMA, "XBOX 4-bit IMA ADPCM"}, {coding_XBOX_IMA_mch, "XBOX 4-bit IMA ADPCM (multichannel)"}, @@ -537,8 +542,6 @@ static const coding_info coding_info_list[] = { {coding_RAD_IMA, "Radical 4-bit IMA ADPCM"}, {coding_RAD_IMA_mono, "Radical 4-bit IMA ADPCM (mono/interleave)"}, {coding_APPLE_IMA4, "Apple Quicktime 4-bit IMA ADPCM"}, - {coding_SNDS_IMA, "Heavy Iron .snds 4-bit IMA ADPCM"}, - {coding_OTNS_IMA, "Omikron: The Nomad Soul 4-bit IMA ADPCM"}, {coding_FSB_IMA, "FSB 4-bit IMA ADPCM"}, {coding_WWISE_IMA, "Audiokinetic Wwise 4-bit IMA ADPCM"}, {coding_REF_IMA, "Reflections 4-bit IMA ADPCM"}, @@ -1051,6 +1054,7 @@ static const meta_info meta_info_list[] = { {meta_XMD, "Konami XMD header"}, {meta_CKS, "Cricket Audio CKS header"}, {meta_CKB, "Cricket Audio CKB header"}, + {meta_WV6, "Gorilla Systems WV6 header"}, #ifdef VGM_USE_FFMPEG {meta_FFmpeg, "FFmpeg supported file format"}, diff --git a/src/libvgmstream.vcproj b/src/libvgmstream.vcproj index cafa822a..585b6835 100644 --- a/src/libvgmstream.vcproj +++ b/src/libvgmstream.vcproj @@ -1414,6 +1414,10 @@ RelativePath=".\meta\ws_aud.c" > + + diff --git a/src/libvgmstream.vcxproj b/src/libvgmstream.vcxproj index e5d37ec4..01508a31 100644 --- a/src/libvgmstream.vcxproj +++ b/src/libvgmstream.vcxproj @@ -430,6 +430,7 @@ + diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters index 0995e443..b7e46897 100644 --- a/src/libvgmstream.vcxproj.filters +++ b/src/libvgmstream.vcxproj.filters @@ -865,6 +865,9 @@ meta\Source Files + + meta\Source Files + meta\Source Files diff --git a/src/meta/meta.h b/src/meta/meta.h index cde8065a..34ff328a 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -771,4 +771,6 @@ VGMSTREAM * init_vgmstream_xmd(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_cks(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_ckb(STREAMFILE *streamFile); +VGMSTREAM * init_vgmstream_wv6(STREAMFILE *streamFile); + #endif /*_META_H*/ diff --git a/src/meta/wv6.c b/src/meta/wv6.c new file mode 100644 index 00000000..bbbf62ec --- /dev/null +++ b/src/meta/wv6.c @@ -0,0 +1,55 @@ +#include "meta.h" +#include "../coding/coding.h" + +/* WV6 - Gorilla Systems PC games [Spy Kids: Mega Mission Zone (PC), Lilo & Stitch: Hawaiian Adventure (PC)] */ +VGMSTREAM * init_vgmstream_wv6(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + off_t start_offset; + int loop_flag, channel_count; + + + /* checks */ + if (!check_extensions(streamFile, "wv6")) + goto fail; + + if (read_32bitLE(0x00,streamFile) != get_streamfile_size(streamFile)) + goto fail; + if (read_32bitBE(0x2c,streamFile) != 0x57563620 || /* "WV6 " */ + read_32bitBE(0x30,streamFile) != 0x494D415F) /* "IMA_" ("WV6 IMA_ADPCM COMPRESSED 16 BIT AUDIO") */ + goto fail; + + /* 0x54/58/5c/60/6c: unknown (reject to catch possible stereo files, but don't seem to exist) */ + if (read_32bitLE(0x54,streamFile) != 0x01 || + read_32bitLE(0x58,streamFile) != 0x01 || + read_32bitLE(0x5c,streamFile) != 0x10 || + read_32bitLE(0x68,streamFile) != 0x01 || + read_32bitLE(0x6c,streamFile) != 0x88) + goto fail; + /* 0x64: PCM size (samples*channels*2) */ + + channel_count = 1; + loop_flag = 0; + start_offset = 0x8c; + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count, loop_flag); + if (!vgmstream) goto fail; + + vgmstream->sample_rate = read_32bitLE(0x60, streamFile); + vgmstream->num_samples = ima_bytes_to_samples(read_32bitLE(0x88,streamFile), channel_count); + + vgmstream->meta_type = meta_WV6; + vgmstream->coding_type = coding_WV6_IMA; + vgmstream->layout_type = layout_none; + + read_string(vgmstream->stream_name,0x1c+1, 0x04,streamFile); + + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} diff --git a/src/vgmstream.c b/src/vgmstream.c index 0c43bbdb..b2799f7e 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -423,6 +423,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = { init_vgmstream_xmd, init_vgmstream_cks, init_vgmstream_ckb, + init_vgmstream_wv6, init_vgmstream_txth, /* should go at the end (lower priority) */ #ifdef VGM_USE_FFMPEG @@ -1062,6 +1063,7 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) { case coding_IMA_int: case coding_DVI_IMA_int: case coding_3DS_IMA: + case coding_WV6_IMA: return 2; case coding_XBOX_IMA: case coding_XBOX_IMA_mch: @@ -1225,6 +1227,7 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) { case coding_DVI_IMA: case coding_DVI_IMA_int: case coding_3DS_IMA: + case coding_WV6_IMA: return 0x01; case coding_MS_IMA: case coding_RAD_IMA: @@ -1238,7 +1241,7 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) { return 0x14; case coding_SNDS_IMA: case coding_OTNS_IMA: - return 0; + return 0; //todo: 0x01? case coding_UBI_IMA: /* variable (PCM then IMA) */ return 0; case coding_XBOX_IMA: @@ -1719,6 +1722,13 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to samples_to_do); } break; + case coding_WV6_IMA: + for (chan=0;chanchannels;chan++) { + decode_wv6_ima(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do); + } + break; case coding_APPLE_IMA4: for (chan=0;chanchannels;chan++) { decode_apple_ima4(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, diff --git a/src/vgmstream.h b/src/vgmstream.h index 1d1b3501..f976b0ab 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -124,6 +124,10 @@ typedef enum { coding_DVI_IMA, /* DVI IMA ADPCM (stereo or mono, high nibble first) */ coding_DVI_IMA_int, /* DVI IMA ADPCM (mono/interleave, high nibble first) */ coding_3DS_IMA, /* 3DS IMA ADPCM */ + coding_SNDS_IMA, /* Heavy Iron Studios .snds IMA ADPCM */ + coding_OTNS_IMA, /* Omikron The Nomad Soul IMA ADPCM */ + coding_WV6_IMA, /* Gorilla Systems WV6 4-bit IMA ADPCM */ + coding_MS_IMA, /* Microsoft IMA ADPCM */ coding_XBOX_IMA, /* XBOX IMA ADPCM */ coding_XBOX_IMA_mch, /* XBOX IMA ADPCM (multichannel) */ @@ -133,8 +137,6 @@ typedef enum { coding_RAD_IMA, /* Radical IMA ADPCM */ coding_RAD_IMA_mono, /* Radical IMA ADPCM (mono/interleave) */ coding_APPLE_IMA4, /* Apple Quicktime IMA4 */ - coding_SNDS_IMA, /* Heavy Iron Studios .snds IMA ADPCM */ - coding_OTNS_IMA, /* Omikron The Nomad Soul IMA ADPCM */ coding_FSB_IMA, /* FMOD's FSB multichannel IMA ADPCM */ coding_WWISE_IMA, /* Audiokinetic Wwise IMA ADPCM */ coding_REF_IMA, /* Reflections IMA ADPCM */ @@ -688,6 +690,7 @@ typedef enum { meta_XMD, /* Konami XMD [Silent Hill 4 (Xbox), Castlevania: Curse of Darkness (Xbox)] */ meta_CKS, /* Cricket Audio stream [Part Time UFO (Android), Mega Man 1-6 (Android)] */ meta_CKB, /* Cricket Audio bank [Fire Emblem Heroes (Android), Mega Man 1-6 (Android)] */ + meta_WV6, /* Gorilla Systems PC games */ #ifdef VGM_USE_FFMPEG meta_FFmpeg,