From 3a49c090a09b5c7d95a3f158009dbfe8d0d6c08e Mon Sep 17 00:00:00 2001 From: Adam Gashlin <agashlin@gmail.com> Date: Thu, 17 Aug 2023 22:20:22 -0700 Subject: [PATCH] Support 32-bit integer PCM in RIFF From masters for a Sonic Origins mod --- src/base/decode.c | 9 +++++++++ src/coding/coding.h | 1 + src/coding/pcm_decoder.c | 15 +++++++++++++++ src/formats.c | 1 + src/meta/riff.c | 4 ++++ src/vgmstream_types.h | 1 + 6 files changed, 31 insertions(+) diff --git a/src/base/decode.c b/src/base/decode.c index 61bc66bb..3a9d2a1e 100644 --- a/src/base/decode.c +++ b/src/base/decode.c @@ -367,6 +367,7 @@ int decode_get_samples_per_frame(VGMSTREAM* vgmstream) { case coding_PCMFLOAT: case coding_PCM24LE: case coding_PCM24BE: + case coding_PCM32LE: return 1; #ifdef VGM_USE_VORBIS case coding_OGG_VORBIS: @@ -594,6 +595,7 @@ int decode_get_frame_size(VGMSTREAM* vgmstream) { case coding_ALAW: return 0x01; case coding_PCMFLOAT: + case coding_PCM32LE: return 0x04; case coding_PCM24LE: case coding_PCM24BE: @@ -907,6 +909,13 @@ void decode_vgmstream(VGMSTREAM* vgmstream, int samples_written, int samples_to_ } break; + case coding_PCM32LE: + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_pcm32le(&vgmstream->ch[ch], buffer+ch, + vgmstream->channels, vgmstream->samples_into_block, samples_to_do); + } + break; + case coding_NDS_IMA: for (ch = 0; ch < vgmstream->channels; ch++) { decode_nds_ima(&vgmstream->ch[ch], buffer+ch, diff --git a/src/coding/coding.h b/src/coding/coding.h index c41f7f5b..edceec6c 100644 --- a/src/coding/coding.h +++ b/src/coding/coding.h @@ -96,6 +96,7 @@ void decode_alaw(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, void decode_pcmfloat(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian); void decode_pcm24le(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_pcm24be(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); +void decode_pcm32le(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); int32_t pcm_bytes_to_samples(size_t bytes, int channels, int bits_per_sample); int32_t pcm24_bytes_to_samples(size_t bytes, int channels); int32_t pcm16_bytes_to_samples(size_t bytes, int channels); diff --git a/src/coding/pcm_decoder.c b/src/coding/pcm_decoder.c index 7a1e61e0..9b7dcccb 100644 --- a/src/coding/pcm_decoder.c +++ b/src/coding/pcm_decoder.c @@ -238,11 +238,26 @@ void decode_pcm24le(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspaci } } +void decode_pcm32le(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { + int i; + int32_t sample_count; + + for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { + off_t offset = stream->offset + i * 0x04; + int32_t v = read_s32le(offset, stream->streamfile); + outbuf[sample_count] = (v >> 16); + } +} + int32_t pcm_bytes_to_samples(size_t bytes, int channels, int bits_per_sample) { if (channels <= 0 || bits_per_sample <= 0) return 0; return ((int64_t)bytes * 8) / channels / bits_per_sample; } +int32_t pcm32_bytes_to_samples(size_t bytes, int channels) { + return pcm_bytes_to_samples(bytes, channels, 32); +} + int32_t pcm24_bytes_to_samples(size_t bytes, int channels) { return pcm_bytes_to_samples(bytes, channels, 24); } diff --git a/src/formats.c b/src/formats.c index c15c82b6..0a397498 100644 --- a/src/formats.c +++ b/src/formats.c @@ -765,6 +765,7 @@ static const coding_info coding_info_list[] = { {coding_PCMFLOAT, "32-bit float PCM"}, {coding_PCM24LE, "24-bit Little Endian PCM"}, {coding_PCM24BE, "24-bit Big Endian PCM"}, + {coding_PCM32LE, "32-bit Little Endian PCM"}, {coding_CRI_ADX, "CRI ADX 4-bit ADPCM"}, {coding_CRI_ADX_fixed, "CRI ADX 4-bit ADPCM (fixed coefficients)"}, diff --git a/src/meta/riff.c b/src/meta/riff.c index 2e5a73fd..e349056a 100644 --- a/src/meta/riff.c +++ b/src/meta/riff.c @@ -146,6 +146,9 @@ static int read_fmt(int big_endian, STREAMFILE* sf, off_t offset, riff_fmt_chunk case 0x0001: /* PCM */ switch (fmt->bps) { + case 32: + fmt->coding_type = coding_PCM32LE; + break; case 24: /* Omori (PC) */ fmt->coding_type = coding_PCM24LE; break; @@ -701,6 +704,7 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) { /* samples, codec init (after setting coding to ensure proper close on failure) */ switch (fmt.coding_type) { + case coding_PCM32LE: case coding_PCM24LE: case coding_PCM16LE: case coding_PCM8_U: diff --git a/src/vgmstream_types.h b/src/vgmstream_types.h index 64ded87e..9e5c053a 100644 --- a/src/vgmstream_types.h +++ b/src/vgmstream_types.h @@ -26,6 +26,7 @@ typedef enum { coding_PCMFLOAT, /* 32-bit float PCM */ coding_PCM24LE, /* little endian 24-bit PCM */ coding_PCM24BE, /* big endian 24-bit PCM */ + coding_PCM32LE, /* little endian 32-bit PCM */ /* ADPCM */ coding_CRI_ADX, /* CRI ADX */