Add Pivotal .psf and decoder [The Great Escape, Conflict: Desert Storm]

This commit is contained in:
bnnm 2019-08-11 19:38:40 +02:00
parent 7f8138fbb5
commit 3bac417a8c
13 changed files with 339 additions and 49 deletions

View File

@ -191,7 +191,7 @@ left together.
Similarly some formats split header and/or data in separate files (.sgh+sgd,
.wav.str+.wav, (file)_L.dsp+(file)_R.dsp, etc). vgmstream will also detect
and use those as needed and must be tegether, even if only one of the two
and use those as needed and must be together, even if only one of the two
will be used to play.
.pos is a small file with 32 bit little endian values: loop start sample
@ -322,7 +322,7 @@ are used in few games.
- Nintendo AFC ADPCM
- ITU-T G.721
- CD-ROM XA ADPCM
- Sony PSX ADPCM a.k.a VAG (standard, badflags, configurable)
- Sony PSX ADPCM a.k.a VAG (standard, badflags, configurable, Pivotal)
- Sony HEVAG
- Electronic Arts EA-XA (stereo, mono, Maxis)
- Electronic Arts EA-XAS (v0, v1)

View File

@ -83,6 +83,7 @@ size_t pcm_bytes_to_samples(size_t bytes, int channels, int bits_per_sample);
/* psx_decoder */
void decode_psx(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int is_badflags);
void decode_psx_configurable(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int frame_size);
void decode_psx_pivotal(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int frame_size);
int ps_find_loop_offsets(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, size_t interleave, int32_t * out_loop_start, int32_t * out_loop_end);
int ps_find_loop_offsets_full(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, size_t interleave, int32_t * out_loop_start, int32_t * out_loop_end);
size_t ps_find_padding(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, size_t interleave, int discard_empty);

View File

@ -3,11 +3,11 @@
/* PS-ADPCM table, defined as rational numbers (as in the spec) */
static const double ps_adpcm_coefs_f[5][2] = {
{ 0.0 , 0.0 },
{ 60.0 / 64.0 , 0.0 },
{ 115.0 / 64.0 , -52.0 / 64.0 },
{ 98.0 / 64.0 , -55.0 / 64.0 },
{ 122.0 / 64.0 , -60.0 / 64.0 },
{ 0.0 , 0.0 }, //{ 0.0 , 0.0 },
{ 0.9375 , 0.0 }, //{ 60.0 / 64.0 , 0.0 },
{ 1.796875 , -0.8125 }, //{ 115.0 / 64.0 , -52.0 / 64.0 },
{ 1.53125 , -0.859375 }, //{ 98.0 / 64.0 , -55.0 / 64.0 },
{ 1.90625 , -0.9375 }, //{ 122.0 / 64.0 , -60.0 / 64.0 },
};
/* PS-ADPCM table, defined as spec_coef*64 (for int implementations) */
@ -101,7 +101,7 @@ void decode_psx(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing
/* PS-ADPCM with configurable frame size and no flag (int math version).
* Found in some PC/PS3 games (FF XI in sizes 3/5/9/41, Afrika in size 4, Blur/James Bond in size 33, etc).
* Found in some PC/PS3 games (FF XI in sizes 0x3/0x5/0x9/0x41, Afrika in size 0x4, Blur/James Bond in size 0x33, etc).
*
* Uses int math to decode, which seems more likely (based on FF XI PC's code in Moogle Toolbox). */
void decode_psx_configurable(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int frame_size) {
@ -114,7 +114,7 @@ void decode_psx_configurable(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int c
/* external interleave (variable size), mono */
bytes_per_frame = frame_size;
samples_per_frame = (bytes_per_frame - 0x01) * 2; /* always 28 */
samples_per_frame = (bytes_per_frame - 0x01) * 2;
frames_in = first_sample / samples_per_frame;
first_sample = first_sample % samples_per_frame;
@ -152,6 +152,56 @@ void decode_psx_configurable(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int c
stream->adpcm_history2_32 = hist2;
}
/* PS-ADPCM from Pivotal games, exactly like psx_cfg but with float math (reverse engineered from the exe) */
void decode_psx_pivotal(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int frame_size) {
off_t frame_offset;
int i, frames_in, sample_count = 0;
size_t bytes_per_frame, samples_per_frame;
uint8_t coef_index, shift_factor;
int32_t hist1 = stream->adpcm_history1_32;
int32_t hist2 = stream->adpcm_history2_32;
float scale;
/* external interleave (variable size), mono */
bytes_per_frame = frame_size;
samples_per_frame = (bytes_per_frame - 0x01) * 2;
frames_in = first_sample / samples_per_frame;
first_sample = first_sample % samples_per_frame;
/* parse frame header */
frame_offset = stream->offset + bytes_per_frame*frames_in;
coef_index = ((uint8_t)read_8bit(frame_offset+0x00,stream->streamfile) >> 4) & 0xf;
shift_factor = ((uint8_t)read_8bit(frame_offset+0x00,stream->streamfile) >> 0) & 0xf;
VGM_ASSERT_ONCE(coef_index > 5 || shift_factor > 12, "PS-ADPCM: incorrect coefs/shift at %x\n", (uint32_t)frame_offset);
if (coef_index > 5) /* just in case */
coef_index = 5;
if (shift_factor > 12) /* same */
shift_factor = 12;
scale = (float)(1.0 / (double)(1 << shift_factor));
/* decode nibbles */
for (i = first_sample; i < first_sample + samples_to_do; i++) {
int32_t sample = 0;
uint8_t nibbles = (uint8_t)read_8bit(frame_offset+0x01+i/2,stream->streamfile);
sample = !(i&1) ? /* low nibble first */
(nibbles >> 0) & 0x0f :
(nibbles >> 4) & 0x0f;
sample = (int16_t)((sample << 12) & 0xf000); /* 16b sign extend + default scale */
sample = sample*scale + ps_adpcm_coefs_f[coef_index][0]*hist1 + ps_adpcm_coefs_f[coef_index][1]*hist2; /* actually substracts negative coefs but whatevs */
outbuf[sample_count] = clamp16(sample);
sample_count += channelspacing;
hist2 = hist1;
hist1 = sample; /* not clamped but no difference */
}
stream->adpcm_history1_32 = hist1;
stream->adpcm_history2_32 = hist2;
}
/* Find loop samples in PS-ADPCM data and return if the file loops.
*
@ -339,7 +389,8 @@ size_t ps_bytes_to_samples(size_t bytes, int channels) {
}
size_t ps_cfg_bytes_to_samples(size_t bytes, size_t frame_size, int channels) {
return bytes / channels / frame_size * 28;
int samples_per_frame = (frame_size - 0x01) * 2;
return bytes / channels / frame_size * samples_per_frame;
}
/* test PS-ADPCM frames for correctness */

View File

@ -333,6 +333,7 @@ static const char* extension_list[] = {
"pona",
"pos",
"ps2stm", //fake extension for .stm (renamed? to be removed?)
"psf",
"psh", //fake extension for .vsv (to be removed)
"psnd",
"psw", //fake extension for .wam (renamed, to be removed)
@ -616,6 +617,7 @@ static const coding_info coding_info_list[] = {
{coding_PSX, "Playstation 4-bit ADPCM"},
{coding_PSX_badflags, "Playstation 4-bit ADPCM (bad flags)"},
{coding_PSX_cfg, "Playstation 4-bit ADPCM (configurable)"},
{coding_PSX_pivotal, "Playstation 4-bit ADPCM (Pivotal)"},
{coding_HEVAG, "Sony HEVAG 4-bit ADPCM"},
{coding_EA_XA, "Electronic Arts EA-XA 4-bit ADPCM v1"},
@ -963,7 +965,6 @@ static const meta_info meta_info_list[] = {
{meta_PS2_VGV, "Rune: Viking Warlord VGV Header"},
{meta_NGC_GCUB, "GCub Header"},
{meta_NGC_SCK_DSP, "The Scorpion King SCK Header"},
{meta_NGC_SWD, "PSF + Standard DSP Headers"},
{meta_CAFF, "Apple Core Audio Format File header"},
{meta_PC_MXST, "Lego Island MxSt Header"},
{meta_SAB, "Team17 SAB header"},
@ -1187,6 +1188,7 @@ static const meta_info meta_info_list[] = {
{meta_SMACKER, "RAD Game Tools SMACKER header"},
{meta_MZRT, "id Software MZRT header"},
{meta_XAVS, "Reflections XAVS header"},
{meta_PSF, "Pivotal PSF header"},
};

View File

@ -2,7 +2,7 @@
#include "../vgmstream.h"
#include "../mixing.h"
#define VGMSTREAM_MAX_SEGMENTS 255
#define VGMSTREAM_MAX_SEGMENTS 512
#define VGMSTREAM_SEGMENT_SAMPLE_BUFFER 8192

View File

@ -1366,10 +1366,14 @@
RelativePath=".\meta\mta2.c"
>
</File>
<File
RelativePath=".\meta\ps3_past.c"
>
</File>
<File
RelativePath=".\meta\ps3_past.c"
>
</File>
<File
RelativePath=".\meta\psf.c"
>
</File>
<File
RelativePath=".\meta\sgxd.c"
>

View File

@ -195,6 +195,7 @@
<ClCompile Include="meta\ps2_wmus.c" />
<ClCompile Include="meta\ps3_ivag.c" />
<ClCompile Include="meta\ps3_past.c" />
<ClCompile Include="meta\psf.c" />
<ClCompile Include="meta\sgxd.c" />
<ClCompile Include="meta\sk_aud.c" />
<ClCompile Include="meta\vawx.c" />

View File

@ -1369,6 +1369,9 @@
<ClCompile Include="meta\ps3_past.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\psf.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\sgxd.c">
<Filter>meta\Source Files</Filter>
</ClCompile>

View File

@ -31,7 +31,6 @@ VGMSTREAM * init_vgmstream_ngc_dsp_std_int(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_idsp_nus3(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_sadb(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_sadf(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ngc_swd(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_idsp_tt(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_idsp_nl(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_wii_wsd(STREAMFILE *streamFile);
@ -852,4 +851,7 @@ VGMSTREAM * init_vgmstream_mzrt(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_xavs(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_psf_single(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_psf_segmented(STREAMFILE * streamFile);
#endif /*_META_H*/

View File

@ -690,33 +690,6 @@ fail:
return NULL;
}
/* SWD - PSF chunks + interleaved dsps [Conflict: Desert Storm 1 & 2] */
VGMSTREAM * init_vgmstream_ngc_swd(STREAMFILE *streamFile) {
dsp_meta dspm = {0};
/* checks */
if (!check_extensions(streamFile, "swd"))
goto fail;
//todo blocked layout when first chunk is 0x50534631 (count + table of 0x0c with offset/sizes)
if (read_32bitBE(0x00,streamFile) != 0x505346d1) /* PSF\0xd1 */
goto fail;
dspm.channel_count = 2;
dspm.max_channels = 2;
dspm.header_offset = 0x08;
dspm.header_spacing = 0x60;
dspm.start_offset = dspm.header_offset + 0x60 * dspm.channel_count;
dspm.interleave = 0x08;
dspm.meta_type = meta_NGC_SWD;
return init_vgmstream_dsp_common(streamFile, &dspm);
fail:
return NULL;
}
/* IDSP - Traveller's Tales header + interleaved dsps [Lego Batman (Wii), Lego Dimensions (Wii U)] */
VGMSTREAM * init_vgmstream_idsp_tt(STREAMFILE *streamFile) {
dsp_meta dspm = {0};

242
src/meta/psf.c Normal file
View File

@ -0,0 +1,242 @@
#include "meta.h"
#include "../layout/layout.h"
#include "../coding/coding.h"
/* PSF single - Pivotal games single segment (external in some PC/Xbox or inside bigfiles) [The Great Escape, Conflict series] */
VGMSTREAM * init_vgmstream_psf_single(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count, sample_rate, rate_value, interleave;
uint32_t psf_config;
uint8_t flags;
size_t data_size;
coding_t codec;
/* checks */
/* .psf: actual extension
* .swd: bigfile extension */
if (!check_extensions(streamFile, "psf,swd"))
goto fail;
if ((read_32bitBE(0x00,streamFile) & 0xFFFFFF00) != 0x50534600) /* "PSF\00" */
goto fail;
flags = read_8bit(0x03,streamFile);
switch(flags) {
case 0xC0: /* [The Great Escape (PS2), Conflict: Desert Storm (PS2)] */
case 0xA1: /* [Conflict: Desert Storm 2 (PS2)] */
case 0x21: /* [Conflict: Desert Storm 2 (PS2), Conflict: Global Storm (PS2)] */
//case 0x22: /* [Conflict: Vietman (PS2)] */ //todo weird size value, stereo, only one found
channel_count = 2;
if (flags == 0x21)
channel_count = 1;
interleave = 0x10;
codec = coding_PSX;
start_offset = 0x08;
break;
case 0x80: /* [The Great Escape (PC/Xbox), Conflict: Desert Storm (Xbox/GC), Conflict: Desert Storm 2 (Xbox)] */
case 0x81: /* [Conflict: Desert Storm 2 (Xbox), Conflict: Vietnam (Xbox)] */
case 0x01: /* [Conflict: Global Storm (Xbox)] */
channel_count = 2;
if (flags == 0x01)
channel_count = 1;
interleave = 0x10;
codec = coding_PSX_pivotal;
start_offset = 0x08;
break;
case 0xD1: /* [Conflict: Desert Storm 2 (GC)] */
channel_count = 2;
interleave = 0x08;
codec = coding_NGC_DSP;
start_offset = 0x08 + 0x60 * channel_count;
break;
default:
goto fail;
}
loop_flag = 0;
psf_config = read_32bitLE(0x04, streamFile);
/* pitch/cents? */
rate_value = (psf_config >> 20) & 0xFFF;
switch(rate_value) {
//case 0xEB5:
//case 0xEB4:
case 0xEB3: sample_rate = 44100; break;
case 0x555: sample_rate = 16000; break;
case 0x355: sample_rate = 11050; break;
case 0x1d5: sample_rate = 6000; break; /* ? */
case 0x1cc: sample_rate = 5000; break;
default:
VGM_LOG("PSF: unknown rate value %x\n", rate_value);
goto fail;
}
data_size = (psf_config & 0xFFFFF) * (interleave * channel_count); /* in blocks */
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_PSF;
vgmstream->sample_rate = sample_rate;
switch(codec) {
case coding_PSX:
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = interleave;
vgmstream->num_samples = ps_bytes_to_samples(data_size, channel_count);
break;
case coding_PSX_pivotal:
vgmstream->coding_type = coding_PSX_pivotal;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = interleave;
vgmstream->num_samples = ps_cfg_bytes_to_samples(data_size, 0x10, channel_count);
break;
case coding_NGC_DSP:
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = interleave;
/* has standard DSP headers at 0x08 */
dsp_read_coefs_be(vgmstream,streamFile,0x08+0x1c,0x60);
dsp_read_hist_be (vgmstream,streamFile,0x08+0x40,0x60);
vgmstream->num_samples = read_32bitBE(0x08, streamFile);//dsp_bytes_to_samples(data_size, channel_count);
break;
default:
goto fail;
}
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
/* PSF segmented - Pivotal games multiple segments (external in some PC/Xbox or inside bigfiles) [The Great Escape, Conflict series] */
VGMSTREAM * init_vgmstream_psf_segmented(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
STREAMFILE* temp_streamFile = NULL;
segmented_layout_data *data = NULL;
int i, segment_count, loop_flag = 0, loop_start = 0, loop_end = 0;
off_t offset;
/* checks */
/* .psf: actual extension
* .swd: bigfile extension */
if (!check_extensions(streamFile, "psf,swd"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x50534660 && /* "PSF\60" [The Great Escape (PC/Xbox/PS2), Conflict: Desert Storm (Xbox/GC)] */
read_32bitBE(0x00,streamFile) != 0x50534631) /* "PSF\31" [Conflict: Desert Storm 2 (Xbox/GC/PS2)] */
goto fail;
segment_count = read_32bitLE(0x04, streamFile);
loop_flag = 0;
offset = 0x08;
offset += 0x0c; /* first segment points to itself? */
segment_count--;
/* build segments */
data = init_layout_segmented(segment_count);
if (!data) goto fail;
for (i = 0; i < segment_count; i++) {
off_t psf_offset;
size_t psf_size;
uint32_t psf_id;
/* mini table */
psf_offset = read_32bitLE(offset + 0x00, streamFile);
/* 0x04-0c: 0x02*4 transition segments (possibly to 4 song variations) */
/* use last section transition as loop */
if (i + 1 == segment_count) {
loop_flag = 1;
loop_start = read_16bitLE(offset + 0x0a, streamFile) - 1; /* also ignore first segment */
loop_end = i;
}
/* multiple segment can point to the same PSF offset (for repeated song sections) */
//todo reuse repeated VGMSTREAMs to improve memory a bit
psf_id = read_32bitBE(psf_offset + 0x00, streamFile);
psf_size = read_32bitLE(psf_offset + 0x04, streamFile);
if (psf_id == 0x505346D1) //todo improve
psf_size = (psf_size & 0xFFFFF) * 0x10;
else
psf_size = (psf_size & 0xFFFFF) * 0x20;
//;VGM_LOG("PSF: offset=%lx, size=%x\n", psf_offset, psf_size);
temp_streamFile = setup_subfile_streamfile(streamFile, psf_offset, psf_size, "psf");
if (!temp_streamFile) goto fail;
data->segments[i] = init_vgmstream_psf_single(temp_streamFile);
if (!data->segments[i]) goto fail;
offset += 0x0c;
}
/* setup VGMSTREAMs */
if (!setup_layout_segmented(data))
goto fail;
vgmstream = allocate_segmented_vgmstream(data,loop_flag, loop_start, loop_end);
if (!vgmstream) goto fail;
vgmstream->stream_size = get_streamfile_size(streamFile);
return vgmstream;
fail:
if (!vgmstream) free_layout_segmented(data);
close_streamfile(temp_streamFile);
close_vgmstream(vgmstream);
return NULL;
}
#if 0
VGMSTREAM * init_vgmstream_sch(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count;
/* checks */
if (!check_extensions(streamFile, "sch"))
goto fail;
/* chunked format (id+size, GC pads to 0x20 and uses BE/inverted ids):
* - SCH\0: start
* - IMUS: points to a external .psf + segment table (same as in .psf, TGE only?)
* - BANK: volume/etc info? points to something?
* - PFSM: single .psf-like file (larger header)
* - PFST: points to single PSF offset (.psf in TGE, or STREAMS.SWD); may be chained to next PFST?
*
* no other info so total subsongs would be count of usable chunks
* in later games, segmented .psf seems to be removed and PFST is used instead
*/
return vgmstream;
fail:
if (!vgmstream) free_layout_layered(data);
close_streamfile(temp_streamFile);
close_vgmstream(vgmstream);
return NULL;
}
#endif

View File

@ -123,7 +123,6 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_sdt,
init_vgmstream_aix,
init_vgmstream_ngc_tydsp,
init_vgmstream_ngc_swd,
init_vgmstream_capdsp,
init_vgmstream_xbox_wvs,
init_vgmstream_ngc_wvs,
@ -467,6 +466,8 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_smk,
init_vgmstream_mzrt,
init_vgmstream_xavs,
init_vgmstream_psf_single,
init_vgmstream_psf_segmented,
/* 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 */
@ -1171,7 +1172,8 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
case coding_HEVAG:
return 28;
case coding_PSX_cfg:
return (vgmstream->interleave_block_size - 1) * 2; /* decodes 1 byte into 2 bytes */
case coding_PSX_pivotal:
return (vgmstream->interleave_block_size - 0x01) * 2; /* size 0x01 header */
case coding_EA_XA:
case coding_EA_XA_int:
@ -1359,6 +1361,7 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
case coding_HEVAG:
return 0x10;
case coding_PSX_cfg:
case coding_PSX_pivotal:
return vgmstream->interleave_block_size;
case coding_EA_XA:
@ -1674,6 +1677,13 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
vgmstream->channels,vgmstream->samples_into_block,samples_to_do, vgmstream->interleave_block_size);
}
break;
case coding_PSX_pivotal:
for (ch = 0; ch < vgmstream->channels; ch++) {
decode_psx_pivotal(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch,
vgmstream->channels,vgmstream->samples_into_block,samples_to_do,
vgmstream->interleave_block_size);
}
break;
case coding_HEVAG:
for (ch = 0; ch < vgmstream->channels; ch++) {
decode_hevag(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch,

View File

@ -104,7 +104,8 @@ typedef enum {
coding_XA, /* CD-ROM XA */
coding_PSX, /* Sony PS ADPCM (VAG) */
coding_PSX_badflags, /* Sony PS ADPCM with custom flag byte */
coding_PSX_cfg, /* Sony PS ADPCM with configurable frame size (FF XI, SGXD type 5, Bizarre Creations) */
coding_PSX_cfg, /* Sony PS ADPCM with configurable frame size (int math) */
coding_PSX_pivotal, /* Sony PS ADPCM with configurable frame size (float math) */
coding_HEVAG, /* Sony PSVita ADPCM */
coding_EA_XA, /* Electronic Arts EA-XA ADPCM v1 (stereo) aka "EA ADPCM" */
@ -389,7 +390,6 @@ typedef enum {
meta_PS2_ENTH, /* Enthusia */
meta_SDT, /* Baldur's Gate - Dark Alliance */
meta_NGC_TYDSP, /* Ty - The Tasmanian Tiger */
meta_NGC_SWD, /* Conflict - Desert Storm 1 & 2 */
meta_CAPDSP, /* Capcom DSP Header [no header_id] */
meta_DC_STR, /* SEGA Stream Asset Builder */
meta_DC_STR_V2, /* variant of SEGA Stream Asset Builder */
@ -712,6 +712,7 @@ typedef enum {
meta_SMACKER,
meta_MZRT,
meta_XAVS,
meta_PSF,
} meta_t;