diff --git a/src/coding/circus_decoder.c b/src/coding/circus_decoder.c new file mode 100644 index 00000000..54dde1a7 --- /dev/null +++ b/src/coding/circus_decoder.c @@ -0,0 +1,29 @@ +#include "coding.h" + + +/* Circus XPCM mode 2 decoding, verified vs EF.exe (info from foo_adpcm/libpcm and https://github.com/lioncash/ExtractData) */ +void decode_circus_adpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { + int i, sample_pos = 0; + int32_t hist = stream->adpcm_history1_32; + int scale = stream->adpcm_scale; + off_t frame_offset = stream->offset; /* frame size is 1 */ + + + for (i = first_sample; i < first_sample + samples_to_do; i++) { + int8_t code = read_8bit(frame_offset+i,stream->streamfile); + + hist += code << scale; + if (code == 0) { + if (scale > 0) + scale--; + } + else if (code == 127 || code == -128) { + if (scale < 8) + scale++; + } + outbuf[sample_pos] = hist; + } + + stream->adpcm_history1_32 = hist; + stream->adpcm_scale = scale; +} diff --git a/src/coding/coding.h b/src/coding/coding.h index aa9d0827..ae1a5338 100644 --- a/src/coding/coding.h +++ b/src/coding/coding.h @@ -165,6 +165,8 @@ void decode_xmd(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, /* derf_decoder */ void decode_derf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); +/* circus_decoder */ +void decode_circus_adpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); /* ea_mt_decoder*/ ea_mt_codec_data *init_ea_mt(int channels, int type); diff --git a/src/formats.c b/src/formats.c index 49eaaad8..ab3eb805 100644 --- a/src/formats.c +++ b/src/formats.c @@ -605,6 +605,7 @@ static const coding_info coding_info_list[] = { {coding_DERF, "Xilam DERF 8-bit DPCM"}, {coding_ACM, "InterPlay ACM"}, {coding_NWA, "VisualArt's NWA DPCM"}, + {coding_CIRCUS_ADPCM, "Circus 8-bit ADPCM"}, {coding_EA_MT, "Electronic Arts MicroTalk"}, diff --git a/src/libvgmstream.vcproj b/src/libvgmstream.vcproj index 7553c96e..97288545 100644 --- a/src/libvgmstream.vcproj +++ b/src/libvgmstream.vcproj @@ -1726,6 +1726,14 @@ RelativePath=".\coding\yamaha_decoder.c" > + + + + diff --git a/src/libvgmstream.vcxproj b/src/libvgmstream.vcxproj index 424d0496..ccfb2082 100644 --- a/src/libvgmstream.vcxproj +++ b/src/libvgmstream.vcxproj @@ -126,6 +126,7 @@ + diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters index 80875ffd..7799f549 100644 --- a/src/libvgmstream.vcxproj.filters +++ b/src/libvgmstream.vcxproj.filters @@ -1417,6 +1417,9 @@ coding\Source Files + + coding\Source Files + meta\Source Files diff --git a/src/meta/xpcm.c b/src/meta/xpcm.c index 15db1ab2..9635bdd2 100644 --- a/src/meta/xpcm.c +++ b/src/meta/xpcm.c @@ -9,7 +9,6 @@ VGMSTREAM * init_vgmstream_xpcm(STREAMFILE *streamFile) { int loop_flag, channel_count, codec, subcodec, sample_rate; - /* checks */ if (!check_extensions(streamFile, "pcm")) goto fail; @@ -27,7 +26,7 @@ VGMSTREAM * init_vgmstream_xpcm(STREAMFILE *streamFile) { /* 0x14: average bitrate */ /* 0x18: block size */ /* 0x1a: output bits (16) */ - start_offset = 0x1c; + start_offset = 0x1c; /* compressed size in codec 0x01/03 */ loop_flag = 0; @@ -47,11 +46,16 @@ VGMSTREAM * init_vgmstream_xpcm(STREAMFILE *streamFile) { vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = 0x02; break; + case 0x02: + if (subcodec != 0) goto fail; + vgmstream->coding_type = coding_CIRCUS_ADPCM; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x01; + break; + case 0x01: /* LZSS + VQ */ - case 0x02: /* ADPCM */ case 0x03: /* unknown */ default: - /* 0x1c contains compressed size for those */ goto fail; } diff --git a/src/vgmstream.c b/src/vgmstream.c index 2e0d290c..2f9550a1 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -1124,6 +1124,7 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) { case coding_DERF: case coding_NWA: case coding_SASSC: + case coding_CIRCUS_ADPCM: return 1; case coding_IMA: @@ -1299,6 +1300,7 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) { case coding_DERF: case coding_NWA: case coding_SASSC: + case coding_CIRCUS_ADPCM: return 0x01; case coding_IMA: @@ -1743,6 +1745,12 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to vgmstream->channels,vgmstream->samples_into_block,samples_to_do); } break; + case coding_CIRCUS_ADPCM: + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_circus_adpcm(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do); + } + break; case coding_IMA: case coding_IMA_int: diff --git a/src/vgmstream.h b/src/vgmstream.h index 5e4ef722..afd3a2b5 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -159,6 +159,7 @@ typedef enum { coding_DERF, /* DERF 8-bit DPCM */ coding_ACM, /* InterPlay ACM */ coding_NWA, /* VisualArt's NWA */ + coding_CIRCUS_ADPCM, /* Circus 8-bit ADPCM */ coding_EA_MT, /* Electronic Arts MicroTalk (linear-predictive speech codec) */