mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-18 07:44:43 +01:00
Add .gin and EA-XAS v0 decoder [Need for Speed Most Wanted]
This commit is contained in:
parent
f90d9c1e5d
commit
5d610be086
@ -101,7 +101,8 @@ void decode_ea_xa_v2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspac
|
||||
void decode_maxis_xa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
|
||||
/* ea_xas_decoder */
|
||||
void decode_ea_xas(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
void decode_ea_xas_v0(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
void decode_ea_xas_v1(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
|
||||
/* sdx2_decoder */
|
||||
void decode_sdx2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
|
@ -9,11 +9,11 @@ static const int EA_XA_TABLE[20] = {
|
||||
0, -1, -3, -4
|
||||
};
|
||||
|
||||
/* EA-XAS, evolution of EA-XA and cousin of MTA2. From FFmpeg (general info) + MTA2 (layout) + EA-XA (decoding)
|
||||
/* EA-XAS v1, evolution of EA-XA/XAS and cousin of MTA2. From FFmpeg (general info) + MTA2 (layout) + EA-XA (decoding)
|
||||
*
|
||||
* Layout: blocks of 0x4c per channel (128 samples), divided into 4 headers + 4 vertical groups of 15 bytes (for parallelism?).
|
||||
* To simplify, always decodes the block and discards unneeded samples, so doesn't use external hist. */
|
||||
void decode_ea_xas(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
void decode_ea_xas_v1(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
int group, row, i;
|
||||
int samples_done = 0, sample_count = 0;
|
||||
|
||||
@ -77,3 +77,64 @@ void decode_ea_xas(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacin
|
||||
stream->offset += 0x4c * channelspacing;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* EA-XAS v0, without complex layouts and closer to EA-XA. Somewhat based on daemon1's decoder */
|
||||
void decode_ea_xas_v0(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
off_t frame_offset;
|
||||
int i;
|
||||
int block_samples, frames_in, samples_done = 0, sample_count = 0;
|
||||
|
||||
/* external interleave (fixed size), mono */
|
||||
block_samples = 32;
|
||||
frames_in = first_sample / block_samples;
|
||||
first_sample = first_sample % block_samples;
|
||||
|
||||
frame_offset = stream->offset + (0x0f+0x02+0x02)*frames_in;
|
||||
|
||||
/* process frames */
|
||||
{
|
||||
int coef1, coef2;
|
||||
int16_t hist1, hist2;
|
||||
uint8_t shift;
|
||||
uint32_t frame_header = (uint32_t)read_32bitLE(frame_offset, stream->streamfile); /* always LE */
|
||||
|
||||
coef1 = EA_XA_TABLE[(uint8_t)(frame_header & 0x0F) + 0];
|
||||
coef2 = EA_XA_TABLE[(uint8_t)(frame_header & 0x0F) + 4];
|
||||
hist2 = (int16_t)(frame_header & 0xFFF0);
|
||||
hist1 = (int16_t)((frame_header >> 16) & 0xFFF0);
|
||||
shift = 20 - ((frame_header >> 16) & 0x0F);
|
||||
|
||||
/* write header samples (needed) */
|
||||
if (sample_count >= first_sample && samples_done < samples_to_do) {
|
||||
outbuf[samples_done * channelspacing] = hist2;
|
||||
samples_done++;
|
||||
}
|
||||
sample_count++;
|
||||
if (sample_count >= first_sample && samples_done < samples_to_do) {
|
||||
outbuf[samples_done * channelspacing] = hist1;
|
||||
samples_done++;
|
||||
}
|
||||
sample_count++;
|
||||
|
||||
/* process nibbles */
|
||||
for (i = 0; i < 0x0f*2; i++) {
|
||||
uint8_t sample_byte = (uint8_t)read_8bit(frame_offset + 0x02 + 0x02 + i/2, stream->streamfile);
|
||||
int sample;
|
||||
|
||||
sample = get_nibble_signed(sample_byte, !(i&1)); /* upper first */
|
||||
sample = sample << shift;
|
||||
sample = (sample + hist1 * coef1 + hist2 * coef2 + 128) >> 8;
|
||||
sample = clamp16(sample);
|
||||
|
||||
if (sample_count >= first_sample && samples_done < samples_to_do) {
|
||||
outbuf[samples_done * channelspacing] = sample;
|
||||
samples_done++;
|
||||
}
|
||||
sample_count++;
|
||||
|
||||
hist2 = hist1;
|
||||
hist1 = sample;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -155,6 +155,7 @@ static const char* extension_list[] = {
|
||||
"gcub",
|
||||
"gcw",
|
||||
"genh",
|
||||
"gin",
|
||||
"gms",
|
||||
"gsb",
|
||||
//"gsf", //conflicts with GBA gsf plugins?
|
||||
@ -586,7 +587,8 @@ static const coding_info coding_info_list[] = {
|
||||
{coding_EA_XA_int, "Electronic Arts EA-XA 4-bit ADPCM v1 (mono/interleave)"},
|
||||
{coding_EA_XA_V2, "Electronic Arts EA-XA 4-bit ADPCM v2"},
|
||||
{coding_MAXIS_XA, "Maxis EA-XA 4-bit ADPCM"},
|
||||
{coding_EA_XAS, "Electronic Arts EA-XAS 4-bit ADPCM"},
|
||||
{coding_EA_XAS_V0, "Electronic Arts EA-XAS 4-bit ADPCM v0"},
|
||||
{coding_EA_XAS_V1, "Electronic Arts EA-XAS 4-bit ADPCM v1"},
|
||||
|
||||
{coding_IMA, "IMA 4-bit ADPCM"},
|
||||
{coding_IMA_int, "IMA 4-bit ADPCM (mono/interleave)"},
|
||||
@ -1155,6 +1157,7 @@ static const meta_info meta_info_list[] = {
|
||||
{meta_DSP_ADPCMX, "AQUASTYLE ADPY header"},
|
||||
{meta_OGG_OPUS, "Ogg Opus header"},
|
||||
{meta_IMC, "iNiS .IMC header"},
|
||||
{meta_GIN, "Electronic Arts Gnsu header"},
|
||||
|
||||
};
|
||||
|
||||
|
@ -576,10 +576,14 @@
|
||||
RelativePath=".\meta\gcsw.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\genh.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\genh.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\gin.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\bar.c"
|
||||
>
|
||||
|
@ -264,6 +264,7 @@
|
||||
<ClCompile Include="meta\gca.c" />
|
||||
<ClCompile Include="meta\gcsw.c" />
|
||||
<ClCompile Include="meta\genh.c" />
|
||||
<ClCompile Include="meta\gin.c" />
|
||||
<ClCompile Include="meta\bar.c" />
|
||||
<ClCompile Include="meta\gsp_gsb.c" />
|
||||
<ClCompile Include="meta\gtd.c" />
|
||||
|
@ -364,6 +364,9 @@
|
||||
<ClCompile Include="meta\genh.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\gin.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\bar.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
@ -640,7 +640,7 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
|
||||
#endif
|
||||
|
||||
case EAAC_CODEC_XAS: /* "Xas1": EA-XAS [Dead Space (PC/PS3)] */
|
||||
vgmstream->coding_type = coding_EA_XAS;
|
||||
vgmstream->coding_type = coding_EA_XAS_V1;
|
||||
vgmstream->layout_type = layout_blocked_ea_sns;
|
||||
break;
|
||||
|
||||
|
53
src/meta/gin.c
Normal file
53
src/meta/gin.c
Normal file
@ -0,0 +1,53 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* .gin - EA engine sounds [Need for Speed: Most Wanted (multi)] */
|
||||
VGMSTREAM * init_vgmstream_gin(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag, channel_count, sample_rate, num_samples;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "gin"))
|
||||
goto fail;
|
||||
|
||||
if (read_32bitBE(0x00,streamFile) != 0x476E7375) /* "Gnsu" */
|
||||
goto fail;
|
||||
|
||||
/* contains mapped values for engine RPM sounds but we'll just play the whole thing */
|
||||
/* 0x04: size? "20\00\00"? */
|
||||
/* 0x08/0c: min/max float RPM? */
|
||||
/* 0x10: RPM up? (pitch/frequency) table size */
|
||||
/* 0x14: RPM ??? table size */
|
||||
/* always LE even on X360/PS3 */
|
||||
|
||||
num_samples = read_32bitLE(0x18, streamFile);
|
||||
sample_rate = read_32bitLE(0x1c, streamFile);
|
||||
start_offset = 0x20 +
|
||||
(read_32bitLE(0x10, streamFile) + 1) * 0x04 +
|
||||
(read_32bitLE(0x14, streamFile) + 1) * 0x04;
|
||||
channel_count = 1;
|
||||
loop_flag = 0;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_GIN;
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->num_samples = num_samples;
|
||||
|
||||
vgmstream->coding_type = coding_EA_XAS_V0;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x13;
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
@ -823,4 +823,6 @@ VGMSTREAM * init_vgmstream_imc_container(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_smp(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_gin(STREAMFILE * streamFile);
|
||||
|
||||
#endif /*_META_H*/
|
||||
|
@ -460,6 +460,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
|
||||
init_vgmstream_imc,
|
||||
init_vgmstream_imc_container,
|
||||
init_vgmstream_smp,
|
||||
init_vgmstream_gin,
|
||||
|
||||
/* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */
|
||||
init_vgmstream_txth, /* proper parsers should supersede TXTH, once added */
|
||||
@ -1188,7 +1189,9 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
|
||||
case coding_EA_XA_V2:
|
||||
case coding_MAXIS_XA:
|
||||
return 28;
|
||||
case coding_EA_XAS:
|
||||
case coding_EA_XAS_V0:
|
||||
return 32;
|
||||
case coding_EA_XAS_V1:
|
||||
return 128;
|
||||
|
||||
case coding_MSADPCM:
|
||||
@ -1370,7 +1373,9 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
|
||||
return 0x0F*vgmstream->channels;
|
||||
case coding_EA_XA_V2:
|
||||
return 0; /* variable (ADPCM frames of 0x0f or PCM frames of 0x3d) */
|
||||
case coding_EA_XAS:
|
||||
case coding_EA_XAS_V0:
|
||||
return 0xF+0x02+0x02;
|
||||
case coding_EA_XAS_V1:
|
||||
return 0x4c*vgmstream->channels;
|
||||
|
||||
case coding_MSADPCM:
|
||||
@ -1706,9 +1711,15 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
|
||||
vgmstream->channels,vgmstream->samples_into_block,samples_to_do, ch);
|
||||
}
|
||||
break;
|
||||
case coding_EA_XAS:
|
||||
case coding_EA_XAS_V0:
|
||||
for (ch = 0; ch < vgmstream->channels; ch++) {
|
||||
decode_ea_xas(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch,
|
||||
decode_ea_xas_v0(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch,
|
||||
vgmstream->channels,vgmstream->samples_into_block,samples_to_do, ch);
|
||||
}
|
||||
break;
|
||||
case coding_EA_XAS_V1:
|
||||
for (ch = 0; ch < vgmstream->channels; ch++) {
|
||||
decode_ea_xas_v1(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch,
|
||||
vgmstream->channels,vgmstream->samples_into_block,samples_to_do, ch);
|
||||
}
|
||||
break;
|
||||
|
@ -106,7 +106,8 @@ typedef enum {
|
||||
coding_EA_XA_int, /* Electronic Arts EA-XA ADPCM v1 (mono/interleave) */
|
||||
coding_EA_XA_V2, /* Electronic Arts EA-XA ADPCM v2 */
|
||||
coding_MAXIS_XA, /* Maxis EA-XA ADPCM */
|
||||
coding_EA_XAS, /* Electronic Arts EA-XAS ADPCM */
|
||||
coding_EA_XAS_V0, /* Electronic Arts EA-XAS ADPCM v0 */
|
||||
coding_EA_XAS_V1, /* Electronic Arts EA-XAS ADPCM v1 */
|
||||
|
||||
coding_IMA, /* IMA ADPCM (stereo or mono, low nibble first) */
|
||||
coding_IMA_int, /* IMA ADPCM (mono/interleave, low nibble first) */
|
||||
@ -712,6 +713,7 @@ typedef enum {
|
||||
meta_DSP_ADPCMX,
|
||||
meta_OGG_OPUS,
|
||||
meta_IMC,
|
||||
meta_GIN,
|
||||
|
||||
} meta_t;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user