From c859482dcd726e06fb6cc2a7102a63ae8a83212e Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 11 Sep 2021 15:49:37 +0200 Subject: [PATCH] Add PCM24 codec [Legend of Mana (PC)] --- src/coding/coding.h | 1 + src/coding/pcm_decoder.c | 39 +++++++++++++++++++++++++-------------- src/decode.c | 10 ++++++++++ src/formats.c | 1 + src/vgmstream.h | 3 ++- 5 files changed, 39 insertions(+), 15 deletions(-) diff --git a/src/coding/coding.h b/src/coding/coding.h index f3f7ffd8..d586264a 100644 --- a/src/coding/coding.h +++ b/src/coding/coding.h @@ -92,6 +92,7 @@ void decode_ulaw(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, void decode_ulaw_int(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_alaw(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); 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); int32_t pcm_bytes_to_samples(size_t bytes, int channels, int bits_per_sample); int32_t pcm16_bytes_to_samples(size_t bytes, int channels); int32_t pcm8_bytes_to_samples(size_t bytes, int channels); diff --git a/src/coding/pcm_decoder.c b/src/coding/pcm_decoder.c index c1bc2c0b..472c8b72 100644 --- a/src/coding/pcm_decoder.c +++ b/src/coding/pcm_decoder.c @@ -2,7 +2,7 @@ #include "../util.h" #include -void decode_pcm16le(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { +void decode_pcm16le(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { int i; int32_t sample_count; @@ -11,7 +11,7 @@ void decode_pcm16le(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspa } } -void decode_pcm16be(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { +void decode_pcm16be(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { int i; int32_t sample_count; @@ -20,7 +20,7 @@ void decode_pcm16be(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspa } } -void decode_pcm16_int(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian) { +void decode_pcm16_int(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian) { int i, sample_count; int16_t (*read_16bit)(off_t,STREAMFILE*) = big_endian ? read_16bitBE : read_16bitLE; @@ -29,7 +29,7 @@ void decode_pcm16_int(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channels } } -void decode_pcm8(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { +void decode_pcm8(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { int i; int32_t sample_count; @@ -38,7 +38,7 @@ void decode_pcm8(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacin } } -void decode_pcm8_int(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { +void decode_pcm8_int(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { int i; int32_t sample_count; @@ -47,7 +47,7 @@ void decode_pcm8_int(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelsp } } -void decode_pcm8_unsigned(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { +void decode_pcm8_unsigned(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { int i; int32_t sample_count; @@ -57,7 +57,7 @@ void decode_pcm8_unsigned(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int chan } } -void decode_pcm8_unsigned_int(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { +void decode_pcm8_unsigned_int(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { int i; int32_t sample_count; @@ -67,7 +67,7 @@ void decode_pcm8_unsigned_int(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int } } -void decode_pcm8_sb(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { +void decode_pcm8_sb(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { int i; int32_t sample_count; @@ -78,7 +78,7 @@ void decode_pcm8_sb(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspa } } -void decode_pcm4(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) { +void decode_pcm4(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) { int i, nibble_shift, is_high_first, is_stereo; int32_t sample_count; int16_t v; @@ -101,7 +101,7 @@ void decode_pcm4(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * ou } } -void decode_pcm4_unsigned(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) { +void decode_pcm4_unsigned(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) { int i, nibble_shift, is_high_first, is_stereo; int32_t sample_count; int16_t v; @@ -149,7 +149,7 @@ static int expand_ulaw(uint8_t ulawbyte) { } /* decodes u-law (ITU G.711 non-linear PCM), from g711.c */ -void decode_ulaw(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { +void decode_ulaw(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { int i, sample_count; for (i=first_sample,sample_count=0; ioffset + i * 0x03; + int v = read_u8(offset+0x00, stream->streamfile) | (read_s16le(offset + 0x01, stream->streamfile) << 8); + outbuf[sample_count] = (v >> 8); + } +} + 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; diff --git a/src/decode.c b/src/decode.c index c632aff2..4280ace5 100644 --- a/src/decode.c +++ b/src/decode.c @@ -368,6 +368,7 @@ int get_vgmstream_samples_per_frame(VGMSTREAM* vgmstream) { case coding_ULAW_int: case coding_ALAW: case coding_PCMFLOAT: + case coding_PCM24LE: return 1; #ifdef VGM_USE_VORBIS case coding_OGG_VORBIS: @@ -592,6 +593,8 @@ int get_vgmstream_frame_size(VGMSTREAM* vgmstream) { return 0x01; case coding_PCMFLOAT: return 0x04; + case coding_PCM24LE: + return 0x03; case coding_SDX2: case coding_SDX2_int: @@ -886,6 +889,13 @@ void decode_vgmstream(VGMSTREAM* vgmstream, int samples_written, int samples_to_ } break; + case coding_PCM24LE: + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_pcm24le(&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/formats.c b/src/formats.c index d99c1d1b..2e176c75 100644 --- a/src/formats.c +++ b/src/formats.c @@ -716,6 +716,7 @@ static const coding_info coding_info_list[] = { {coding_ULAW_int, "8-bit u-Law with 1 byte interleave (block)"}, {coding_ALAW, "8-bit a-Law"}, {coding_PCMFLOAT, "32-bit float PCM"}, + {coding_PCM24LE, "24-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/vgmstream.h b/src/vgmstream.h index 39d7722f..81133467 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -67,7 +67,8 @@ typedef enum { coding_ULAW_int, /* 8-bit u-Law (non-linear PCM) with sample-level interleave (for blocks) */ coding_ALAW, /* 8-bit a-Law (non-linear PCM) */ - coding_PCMFLOAT, /* 32 bit float PCM */ + coding_PCMFLOAT, /* 32-bit float PCM */ + coding_PCM24LE, /* 24-bit PCM */ /* ADPCM */ coding_CRI_ADX, /* CRI ADX */