From c770490b3d418bc1c648a288ffad7ed9fb738504 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 8 Oct 2017 17:51:54 +0200 Subject: [PATCH] Add AL2 meta + A-law decoder [Conquest of Elysium 3 (PC)] --- fb2k/foo_filetypes.h | 1 + src/coding/coding.h | 1 + src/coding/pcm_decoder.c | 36 +++++++++++++++++++++++++++- src/formats.c | 3 +++ src/libvgmstream.vcproj | 4 ++++ src/libvgmstream.vcxproj | 1 + src/libvgmstream.vcxproj.filters | 3 +++ src/meta/meta.h | 2 ++ src/meta/pc_al2.c | 40 ++++++++++++++++++++++++++++++++ src/vgmstream.c | 10 ++++++++ src/vgmstream.h | 4 +++- 11 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 src/meta/pc_al2.c diff --git a/fb2k/foo_filetypes.h b/fb2k/foo_filetypes.h index 5093ba36..b23db295 100644 --- a/fb2k/foo_filetypes.h +++ b/fb2k/foo_filetypes.h @@ -39,6 +39,7 @@ VGMSTREAM_DECLARE_FILE_TYPE("AIFCL", aifcl); //"aiff", //common VGMSTREAM_DECLARE_FILE_TYPE("AIX", aix); VGMSTREAM_DECLARE_FILE_TYPE("AKB", akb); +VGMSTREAM_DECLARE_FILE_TYPE("AL2", al2); VGMSTREAM_DECLARE_FILE_TYPE("AMTS", amts); VGMSTREAM_DECLARE_FILE_TYPE("AO", ao); VGMSTREAM_DECLARE_FILE_TYPE("AS4", as4); diff --git a/src/coding/coding.h b/src/coding/coding.h index faac9842..1976a5e1 100644 --- a/src/coding/coding.h +++ b/src/coding/coding.h @@ -64,6 +64,7 @@ void decode_pcm8_sb_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channels void decode_pcm8_unsigned_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_pcm8_unsigned(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_ulaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); +void decode_alaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_pcmfloat(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian); size_t pcm_bytes_to_samples(size_t bytes, int channels, int bits_per_sample); diff --git a/src/coding/pcm_decoder.c b/src/coding/pcm_decoder.c index 47c69cd0..3a8e813a 100644 --- a/src/coding/pcm_decoder.c +++ b/src/coding/pcm_decoder.c @@ -87,7 +87,7 @@ void decode_pcm16LE_XOR_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int chan } } -/* decodes u-law (ITU G.711 non-linear PCM) */ +/* decodes u-law (ITU G.711 non-linear PCM), from g711.c */ void decode_ulaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { int i; int32_t sample_count; @@ -119,6 +119,40 @@ void decode_ulaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, } } +/* decodes a-law (ITU G.711 non-linear PCM), from g711.c */ +void decode_alaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { + int i; + int32_t sample_count; + int sign, segment, quantization, sample; + + + for (i=first_sample,sample_count=0; ioffset+i,stream->streamfile); + + alawbyte ^= 0x55; + sign = (alawbyte & 0x80); + segment = (alawbyte & 0x70) >> 4; /* exponent */ + quantization = alawbyte & 0x0F; /* mantissa */ + + sample = (quantization << 4); + switch (segment) { + case 0: + sample += 8; + break; + case 1: + sample += 0x108; + break; + default: + sample += 0x108; + sample <<= segment - 1; + break; + } + sample = (sign) ? sample : -sample; + + outbuf[sample_count] = sample; + } +} + void decode_pcmfloat(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian) { int i, sample_count; int32_t (*read_32bit)(off_t,STREAMFILE*) = big_endian ? read_32bitBE : read_32bitLE; diff --git a/src/formats.c b/src/formats.c index 8fa7d53e..25986964 100644 --- a/src/formats.c +++ b/src/formats.c @@ -32,6 +32,7 @@ static const char* extension_list[] = { //"aiff", //common "aix", "akb", + "al2", "amts", //fake extension (to be removed) "ao", //txth/reserved [Cloudphobia (PC)] "as4", @@ -410,6 +411,7 @@ static const coding_info coding_info_list[] = { {coding_PCM8_int, "8-bit PCM with 1 byte interleave"}, {coding_PCM8_SB_int, "8-bit PCM with sign bit, 1 byte interleave"}, {coding_ULAW, "8-bit u-Law"}, + {coding_ALAW, "8-bit a-Law"}, {coding_PCMFLOAT, "32-bit float PCM"}, {coding_CRI_ADX, "CRI ADX 4-bit ADPCM"}, {coding_CRI_ADX_exp, "CRI ADX 4-bit ADPCM with exponential scale"}, @@ -890,6 +892,7 @@ static const meta_info meta_info_list[] = { {meta_EA_SNU, "Electronic Arts SNU header"}, {meta_AWC, "Rockstar AWC header"}, {meta_NSW_OPUS, ".OPUS header"}, + {meta_PC_AL2, "Illwinter Game Design AL2 raw header"}, #ifdef VGM_USE_VORBIS {meta_OGG_VORBIS, "Ogg Vorbis"}, diff --git a/src/libvgmstream.vcproj b/src/libvgmstream.vcproj index 94aae551..3437c9eb 100644 --- a/src/libvgmstream.vcproj +++ b/src/libvgmstream.vcproj @@ -658,6 +658,10 @@ RelativePath=".\meta\pc_adp.c" > + + diff --git a/src/libvgmstream.vcxproj b/src/libvgmstream.vcxproj index 4e407b38..e2386e90 100644 --- a/src/libvgmstream.vcxproj +++ b/src/libvgmstream.vcxproj @@ -288,6 +288,7 @@ + diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters index 83392562..b58267b6 100644 --- a/src/libvgmstream.vcxproj.filters +++ b/src/libvgmstream.vcxproj.filters @@ -391,6 +391,9 @@ meta\Source Files + + meta\Source Files + meta\Source Files diff --git a/src/meta/meta.h b/src/meta/meta.h index 4afb986e..a8da4c87 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -684,4 +684,6 @@ VGMSTREAM * init_vgmstream_awc(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_nsw_opus(STREAMFILE * streamFile); +VGMSTREAM * init_vgmstream_pc_al2(STREAMFILE * streamFile); + #endif /*_META_H*/ diff --git a/src/meta/pc_al2.c b/src/meta/pc_al2.c new file mode 100644 index 00000000..33f01c9d --- /dev/null +++ b/src/meta/pc_al2.c @@ -0,0 +1,40 @@ +#include "meta.h" +#include "../coding/coding.h" + +/* AL" - headerless a-law, found in Conquest of Elysium 3 (PC) */ +VGMSTREAM * init_vgmstream_pc_al2(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + off_t start_offset; + int loop_flag = 0, channel_count; + + + if ( !check_extensions(streamFile,"al2")) + goto fail; + + channel_count = 2; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + vgmstream->sample_rate = 22050; + vgmstream->coding_type = coding_ALAW; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x01; + vgmstream->meta_type = meta_PC_AL2; + vgmstream->num_samples = pcm_bytes_to_samples(get_streamfile_size(streamFile), channel_count, 8); + if (loop_flag) { + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = vgmstream->num_samples; + } + + start_offset = 0; + + 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 517d345d..0c871582 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -370,6 +370,7 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = { init_vgmstream_ea_snu, init_vgmstream_awc, init_vgmstream_nsw_opus, + init_vgmstream_pc_al2, init_vgmstream_txth, /* should go at the end (lower priority) */ #ifdef VGM_USE_FFMPEG @@ -982,6 +983,7 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) { case coding_PCM8_SB_int: case coding_PCM8_U_int: case coding_ULAW: + case coding_ALAW: case coding_PCMFLOAT: return 1; #ifdef VGM_USE_VORBIS @@ -1141,6 +1143,7 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) { case coding_PCM8_SB_int: case coding_PCM8_U_int: case coding_ULAW: + case coding_ALAW: return 1; case coding_PCMFLOAT: return 4; @@ -1379,6 +1382,13 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to samples_to_do); } break; + case coding_ALAW: + for (chan=0;chanchannels;chan++) { + decode_alaw(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do); + } + break; case coding_PCMFLOAT: for (chan=0;chanchannels;chan++) { decode_pcmfloat(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, diff --git a/src/vgmstream.h b/src/vgmstream.h index a3c106b6..6e21528d 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -86,6 +86,7 @@ typedef enum { coding_PCM8_SB_int, /* 8-bit PCM, sign bit (others are 2's complement) with sample-level interleave */ coding_ULAW, /* 8-bit u-Law (non-linear PCM) */ + coding_ALAW, /* 8-bit a-Law (non-linear PCM) */ coding_PCMFLOAT, /* 32 bit float PCM */ @@ -352,7 +353,7 @@ typedef enum { meta_RWX, /* Air Force Delta Storm (XBOX) */ meta_XWB, /* Microsoft XACT framework (Xbox, X360, Windows) */ meta_PS2_XA30, /* Driver - Parallel Lines (PS2) */ - meta_MUSC, /* Spyro Games, possibly more */ + meta_MUSC, /* Krome PS2 games */ meta_MUSX_V004, /* Spyro Games, possibly more */ meta_MUSX_V005, /* Spyro Games, possibly more */ meta_MUSX_V006, /* Spyro Games, possibly more */ @@ -627,6 +628,7 @@ typedef enum { meta_EA_SNU, /* Electronic Arts SNU (Dead Space) */ meta_AWC, /* Rockstar AWC (GTA5, RDR) */ meta_NSW_OPUS, /* Lego City Undercover (Switch) */ + meta_PC_AL2, /* Conquest of Elysium 3 (PC) */ #ifdef VGM_USE_VORBIS meta_OGG_VORBIS, /* Ogg Vorbis */