mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-28 16:30:54 +01:00
Add From Software .xps/.xps+dat [Metal Wolf Chaos (Xbox), Otogi (Xbox)]
This commit is contained in:
parent
b3d77689a7
commit
42bc5de623
@ -472,6 +472,7 @@ static const char* extension_list[] = {
|
||||
"xwb",
|
||||
"xmd",
|
||||
"xopus",
|
||||
"xps",
|
||||
"xwc",
|
||||
"xwm",
|
||||
"xwma",
|
||||
@ -1112,7 +1113,8 @@ static const meta_info meta_info_list[] = {
|
||||
{meta_VS_FFX, "Square VS header"},
|
||||
{meta_NWAV, "Chunsoft NWAV header"},
|
||||
{meta_XPCM, "Circus XPCM header"},
|
||||
{meta_MSF_TAMASOFT, "TamaSoft MSF header"},
|
||||
{meta_MSF_TAMASOFT, "Tama-Soft MSF header"},
|
||||
{meta_XPS_DAT, "From Software .XPS+DAT header"},
|
||||
|
||||
};
|
||||
|
||||
|
@ -1625,6 +1625,10 @@
|
||||
<File
|
||||
RelativePath=".\meta\xpcm.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\xps.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\xss.c"
|
||||
|
@ -481,6 +481,7 @@
|
||||
<ClCompile Include="meta\xnb.c" />
|
||||
<ClCompile Include="meta\xopus.c" />
|
||||
<ClCompile Include="meta\xpcm.c" />
|
||||
<ClCompile Include="meta\xps.c" />
|
||||
<ClCompile Include="meta\xss.c" />
|
||||
<ClCompile Include="meta\xvag.c" />
|
||||
<ClCompile Include="meta\xmd.c" />
|
||||
|
@ -1465,6 +1465,9 @@
|
||||
<ClCompile Include="meta\xpcm.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\xps.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\x360_cxs.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
@ -810,4 +810,7 @@ VGMSTREAM * init_vgmstream_xpcm(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_msf_tamasoft(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_xps_dat(STREAMFILE * streamFile);
|
||||
VGMSTREAM * init_vgmstream_xps(STREAMFILE * streamFile);
|
||||
|
||||
#endif /*_META_H*/
|
||||
|
223
src/meta/xps.c
Normal file
223
src/meta/xps.c
Normal file
@ -0,0 +1,223 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
static void read_xps_name(VGMSTREAM *vgmstream, STREAMFILE *streamFile, int file_id);
|
||||
|
||||
/* .XPS+DAT - From Software games streams [Metal Wolf Chaos (Xbox), Otogi (Xbox)] */
|
||||
VGMSTREAM * init_vgmstream_xps_dat(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
STREAMFILE * streamData = NULL;
|
||||
off_t start_offset, header_offset;
|
||||
size_t stream_size;
|
||||
int loop_flag, channel_count, sample_rate, codec, loop_start_sample, loop_end_sample, file_id;
|
||||
int total_subsongs, target_subsong = streamFile->stream_index;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "xps"))
|
||||
goto fail;
|
||||
|
||||
if (read_32bitLE(0x00,streamFile) != get_streamfile_size(streamFile))
|
||||
goto fail;
|
||||
if (read_32bitBE(0x0c,streamFile) != 0x64696666) /* "diff" */
|
||||
goto fail;
|
||||
|
||||
/* handle .xps+dat (bank .xps are done below) */
|
||||
streamData = open_streamfile_by_ext(streamFile, "dat");
|
||||
if (!streamData) goto fail;
|
||||
|
||||
/* 0x00: approximate file size */
|
||||
|
||||
total_subsongs = read_32bitLE(0x04,streamData);
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||
|
||||
header_offset = 0x20 + 0x94*(target_subsong-1); /* could start at 0x0c too */
|
||||
|
||||
file_id = read_32bitLE(header_offset+0x00,streamData);
|
||||
start_offset = read_32bitLE(header_offset+0x04,streamData);
|
||||
stream_size = read_32bitLE(header_offset+0x08,streamData);
|
||||
/* 0x0c: loop start offset? */
|
||||
/* 0x10: loop end offset? */
|
||||
/* 0x14: always null? */
|
||||
codec = read_16bitLE(header_offset+0x18,streamData);
|
||||
channel_count = read_16bitLE(header_offset+0x1a,streamData);
|
||||
sample_rate = read_32bitLE(header_offset+0x1c,streamData);
|
||||
/* 0x20: average bitrate */
|
||||
/* 0x24: block size, bps */
|
||||
loop_flag = read_32bitLE(header_offset+0x5c,streamData);
|
||||
loop_start_sample = read_32bitLE(header_offset+0x6c,streamData);
|
||||
loop_end_sample = read_32bitLE(header_offset+0x70,streamData) + 1; /* a "smpl" chunk basically */
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->meta_type = meta_XPS_DAT;
|
||||
vgmstream->loop_start_sample = loop_start_sample;
|
||||
vgmstream->loop_end_sample = loop_end_sample;
|
||||
vgmstream->num_streams = total_subsongs;
|
||||
vgmstream->stream_size = stream_size;
|
||||
|
||||
switch(codec) {
|
||||
case 0x01:
|
||||
vgmstream->coding_type = coding_PCM16LE;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x02;
|
||||
vgmstream->num_samples = pcm_bytes_to_samples(stream_size, channel_count, 16);
|
||||
break;
|
||||
|
||||
case 0x69:
|
||||
vgmstream->coding_type = coding_XBOX_IMA;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->num_samples = xbox_ima_bytes_to_samples(stream_size, channel_count);
|
||||
break;
|
||||
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
read_xps_name(vgmstream, streamFile, file_id);
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamData,start_offset))
|
||||
goto fail;
|
||||
|
||||
close_streamfile(streamData);
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_streamfile(streamData);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void read_xps_name(VGMSTREAM *vgmstream, STREAMFILE *streamFile, int file_id) {
|
||||
int i, entries;
|
||||
int name_id = -1, udss_name_id;
|
||||
off_t entry_offset = 0x10;
|
||||
|
||||
|
||||
/* main section + stream sections (usually same number but not always) */
|
||||
entries = read_32bitLE(0x04,streamFile);
|
||||
|
||||
/* "sid\0" entries: find name_id of file_id */
|
||||
for (i = 0; i < entries; i++) {
|
||||
off_t entry_base = entry_offset;
|
||||
size_t entry_size = read_32bitLE(entry_base+0x00,streamFile);
|
||||
uint32_t entry_id = read_32bitBE(entry_base+0x04,streamFile);
|
||||
size_t entry_pad = read_32bitLE(entry_base+0x08,streamFile);
|
||||
/* 0x0c: always null, rest: entry (format varies) */
|
||||
|
||||
entry_offset += entry_size + entry_pad + 0x10;
|
||||
|
||||
/* sound info entry */
|
||||
if (entry_id == 0x73696400) { /* "sid\0" */
|
||||
int entry_file_id = read_32bitLE(entry_base+0x10,streamFile);
|
||||
int entry_name_id = read_32bitLE(entry_base+0x14,streamFile);
|
||||
if (entry_file_id == file_id && name_id == -1) {
|
||||
name_id = entry_name_id;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* sound stream entry, otherwise no good */
|
||||
if (entry_id != 0x75647373) { /* "udss" */
|
||||
goto fail;
|
||||
}
|
||||
|
||||
udss_name_id = read_32bitLE(entry_base+0x10,streamFile);
|
||||
if (udss_name_id == name_id) {
|
||||
off_t name_offset = entry_base + 0x10 + 0x08;
|
||||
size_t name_size = entry_size - 0x08; /* includes null */
|
||||
read_string(vgmstream->stream_name,name_size, name_offset,streamFile);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fail:
|
||||
return;
|
||||
}
|
||||
|
||||
/* .XPS - From Software games banks [Metal Wolf Chaos (Xbox), Otogi (Xbox)] */
|
||||
VGMSTREAM * init_vgmstream_xps(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
STREAMFILE * streamData = NULL;
|
||||
int i, entries;
|
||||
off_t entry_offset = 0x10;
|
||||
int total_subsongs, target_subsong = streamFile->stream_index;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "xps"))
|
||||
goto fail;
|
||||
|
||||
if (read_32bitLE(0x00,streamFile) != get_streamfile_size(streamFile))
|
||||
goto fail;
|
||||
if (read_32bitBE(0x0c,streamFile) != 0x64696666) /* "diff" */
|
||||
goto fail;
|
||||
|
||||
/* handle .xps alone (stream .xps+data are done above) */
|
||||
streamData = open_streamfile_by_ext(streamFile, "dat");
|
||||
if (streamData) goto fail;
|
||||
|
||||
/* main section + bank sections (usually same number but not always) */
|
||||
entries = read_32bitLE(0x04,streamFile);
|
||||
|
||||
total_subsongs = 0;
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
if (target_subsong < 0 /*|| target_subsong > total_subsongs || total_subsongs < 1*/) goto fail;
|
||||
|
||||
|
||||
/* parse entries: skip (there is probably a stream/bank flag here) */
|
||||
for (i = 0; i < entries; i++) {
|
||||
off_t entry_base = entry_offset;
|
||||
size_t entry_size = read_32bitLE(entry_base+0x00,streamFile);
|
||||
uint32_t entry_id = read_32bitBE(entry_base+0x04,streamFile);
|
||||
size_t entry_pad = read_32bitLE(entry_base+0x08,streamFile);
|
||||
/* 0x0c: always null, rest: entry (format varies) */
|
||||
|
||||
entry_offset += entry_size + entry_pad + 0x10;
|
||||
|
||||
/* sound info entry */
|
||||
if (entry_id == 0x73696400) { /* "sid\0" */
|
||||
/* keep looking for sound banks */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* sound bank entry, otherwise no good */
|
||||
if (entry_id != 0x75647362) { /* "udsb" */
|
||||
goto fail;
|
||||
}
|
||||
|
||||
total_subsongs++;
|
||||
|
||||
/* open internal RIFF */
|
||||
if (target_subsong == total_subsongs && vgmstream == NULL) {
|
||||
STREAMFILE* temp_streamFile;
|
||||
off_t subsong_offset = entry_base+0x18;
|
||||
size_t subsong_size = read_32bitLE(entry_base+0x14,streamFile);
|
||||
|
||||
temp_streamFile = setup_subfile_streamfile(streamFile, subsong_offset,subsong_size, "wav");
|
||||
if (!temp_streamFile) goto fail;
|
||||
|
||||
vgmstream = init_vgmstream_riff(temp_streamFile);
|
||||
close_streamfile(temp_streamFile);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* subsong not found */
|
||||
if (!vgmstream)
|
||||
goto fail;
|
||||
|
||||
vgmstream->num_streams = total_subsongs;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_streamfile(streamData);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
@ -450,6 +450,8 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
|
||||
init_vgmstream_nwav,
|
||||
init_vgmstream_xpcm,
|
||||
init_vgmstream_msf_tamasoft,
|
||||
init_vgmstream_xps_dat,
|
||||
init_vgmstream_xps,
|
||||
|
||||
/* 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 */
|
||||
|
@ -706,6 +706,7 @@ typedef enum {
|
||||
meta_NWAV,
|
||||
meta_XPCM,
|
||||
meta_MSF_TAMASOFT,
|
||||
meta_XPS_DAT,
|
||||
|
||||
} meta_t;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user