diff --git a/src/coding/coding.h b/src/coding/coding.h index f553c4f7..92efe52d 100644 --- a/src/coding/coding.h +++ b/src/coding/coding.h @@ -62,6 +62,8 @@ void decode_baf_adpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspa void decode_hevag_adpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); +void decode_short_vag_adpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); + void decode_xa(VGMSTREAM * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); void init_get_high_nibble(VGMSTREAM * vgmstream); diff --git a/src/coding/psx_decoder.c b/src/coding/psx_decoder.c index 21bc0b8c..c8484269 100644 --- a/src/coding/psx_decoder.c +++ b/src/coding/psx_decoder.c @@ -14,7 +14,6 @@ static const double VAG_f[5][2] = { { 98.0 / 64.0 , -55.0 / 64.0 }, { 122.0 / 64.0 , -60.0 / 64.0 } }; -#if VAG_USE_INTEGER_TABLE /* PS ADPCM table */ static const int8_t VAG_coefs[5][2] = { { 0 , 0 }, @@ -23,7 +22,6 @@ static const int8_t VAG_coefs[5][2] = { { 98 , -55 }, { 122 , -60 } }; -#endif /* PSVita ADPCM table */ @@ -418,7 +416,7 @@ void decode_hevag_adpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channels byte = read_8bit(stream->offset+(framesin*16)+2+i/2,stream->streamfile); scale = byte & 0x0f; } - if (scale > 7) { /* sign fix */ + if (scale > 7) { /* sign extend */ scale = scale - 16; } @@ -441,3 +439,59 @@ void decode_hevag_adpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channels stream->adpcm_history3_32 = hist3; stream->adpcm_history4_32 = hist4; } + + +/** + * Short VAG ADPCM, found in PS3 Afrika (SGDX type 5). + * Uses 8 byte blocks and no flag. + */ +void decode_short_vag_adpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { + + uint8_t predict_nr, shift, byte; + int16_t scale = 0; + + int32_t sample; + int32_t hist1 = stream->adpcm_history1_32; + int32_t hist2 = stream->adpcm_history2_32; + + int i, sample_count; + + + int framesin = first_sample / 6; + + /* 2 byte header: predictor = 1st, shift = 2nd */ + byte = (uint8_t)read_8bit(stream->offset+framesin*8+0,stream->streamfile); + predict_nr = byte >> 4; + shift = byte & 0x0f; + + first_sample = first_sample % 6; + + for (i = first_sample, sample_count = 0; i < first_sample + samples_to_do; i++, sample_count += channelspacing) { + sample = 0; + + if (predict_nr < 5) { + + if (i & 1) {/* odd/even nibble */ + scale = byte >> 4; + } else { + byte = (uint8_t)read_8bit(stream->offset+(framesin*8)+1+i/2,stream->streamfile); + scale = (byte & 0x0f); + } + /*if (scale > 7) { + scale = scale - 16; + }*/ + scale = scale << 12; /* shift + sign extend only if scale is int16_t */ + + sample = (hist1 * VAG_coefs[predict_nr][0] + + hist2 * VAG_coefs[predict_nr][1] ) / 64; + sample = sample + (scale >> shift); + } + + outbuf[sample_count] = clamp16(sample); + hist2 = hist1; + hist1 = sample; + } + + stream->adpcm_history1_32 = hist1; + stream->adpcm_history2_32 = hist2; +} diff --git a/src/meta/ps3_sgh_sgb.c b/src/meta/ps3_sgh_sgb.c index e299df3b..ce0ec106 100644 --- a/src/meta/ps3_sgh_sgb.c +++ b/src/meta/ps3_sgh_sgb.c @@ -194,21 +194,12 @@ VGMSTREAM * init_vgmstream_ps3_sgdx(STREAMFILE *streamFile) { break; } #endif - - case 0x05: /* todo PCM? */ - goto fail; - - /* - vgmstream->coding_type = coding_PCM16LE; - if (vgmstream->channels > 1) { - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = 0x1; - } else { - vgmstream->layout_type = layout_none; - } + case 0x05: /* Short VAG ADPCM */ + vgmstream->coding_type = coding_SHORT_VAG_ADPCM; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x4; break; - */ #ifdef VGM_USE_FFMPEG case 0x06: /* AC3 */ diff --git a/src/vgmstream.c b/src/vgmstream.c index c6439713..0595d37a 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -1035,6 +1035,8 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) { case coding_HEVAG_ADPCM: case coding_XA: return 28; + case coding_SHORT_VAG_ADPCM: + return 6; case coding_XBOX: case coding_INT_XBOX: case coding_BAF_ADPCM: @@ -1164,6 +1166,8 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) { case coding_invert_PSX: case coding_NDS_PROCYON: return 16; + case coding_SHORT_VAG_ADPCM: + return 4; case coding_XA: return 14*vgmstream->channels; case coding_XBOX: @@ -1444,6 +1448,13 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to samples_to_do); } break; + case coding_SHORT_VAG_ADPCM: + for (chan=0;chanchannels;chan++) { + decode_short_vag_adpcm(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do); + } + break; case coding_XA: for (chan=0;chanchannels;chan++) { decode_xa(vgmstream,buffer+samples_written*vgmstream->channels+chan, @@ -1974,6 +1985,9 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) { case coding_HEVAG_ADPCM: snprintf(temp,TEMPSIZE,"PSVita HEVAG ADPCM"); break; + case coding_SHORT_VAG_ADPCM: + snprintf(temp,TEMPSIZE,"Short VAG (SGXD type 5) ADPCM"); + break; case coding_XA: snprintf(temp,TEMPSIZE,"CD-ROM XA 4-bit ADPCM"); break; diff --git a/src/vgmstream.h b/src/vgmstream.h index 7dcddd27..58930651 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -94,6 +94,7 @@ typedef enum { coding_FFXI, /* FF XI PSX-ish ADPCM */ coding_BAF_ADPCM, /* Bizarre Creations PSX-ish ADPCM */ coding_HEVAG_ADPCM, /* PSVita games */ + coding_SHORT_VAG_ADPCM, /* SGXD type 5 (PS3 Afrika) */ coding_XA, /* PSX CD-XA */ coding_XBOX, /* XBOX IMA */ coding_INT_XBOX, /* XBOX 'real interleaved' IMA */