Add AL2 meta + A-law decoder [Conquest of Elysium 3 (PC)]

This commit is contained in:
bnnm 2017-10-08 17:51:54 +02:00
parent 874694bd0a
commit c770490b3d
11 changed files with 103 additions and 2 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
uint8_t alawbyte = read_8bit(stream->offset+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;

View File

@ -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"},

View File

@ -658,6 +658,10 @@
RelativePath=".\meta\pc_adp.c"
>
</File>
<File
RelativePath=".\meta\pc_al2.c"
>
</File>
<File
RelativePath=".\meta\pc_mxst.c"
>

View File

@ -288,6 +288,7 @@
<ClCompile Include="meta\ogl.c" />
<ClCompile Include="meta\otm.c" />
<ClCompile Include="meta\p3d.c" />
<ClCompile Include="meta\pc_al2.c" />
<ClCompile Include="meta\pc_mxst.c" />
<ClCompile Include="meta\pc_smp.c" />
<ClCompile Include="meta\pc_sob.c" />

View File

@ -391,6 +391,9 @@
<ClCompile Include="meta\p3d.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\pc_al2.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\pc_mxst.c">
<Filter>meta\Source Files</Filter>
</ClCompile>

View File

@ -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*/

40
src/meta/pc_al2.c Normal file
View File

@ -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;
}

View File

@ -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;chan<vgmstream->channels;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;chan<vgmstream->channels;chan++) {
decode_pcmfloat(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,

View File

@ -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 */