Add 2MSF and clean WMSF [Super Robot Taisen OG: The Moon Dwellers (PS4)]

This commit is contained in:
bnnm 2018-10-27 23:10:03 +02:00
parent 7cde6bdf8b
commit 0e16a309e2
9 changed files with 129 additions and 26 deletions

View File

@ -352,4 +352,8 @@ typedef struct {
int r_bits(vgm_bitstream * ib, int num_bits, uint32_t * value); int r_bits(vgm_bitstream * ib, int num_bits, uint32_t * value);
int w_bits(vgm_bitstream * ob, int num_bits, uint32_t value); int w_bits(vgm_bitstream * ob, int num_bits, uint32_t value);
/* helper to pass a wrapped, clamped, fake extension-ed, SF to another meta */
STREAMFILE* setup_subfile_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size, char* extension);
#endif /*_CODING_H*/ #endif /*_CODING_H*/

View File

@ -1080,3 +1080,31 @@ int w_bits(vgm_bitstream * ob, int num_bits, uint32_t value) {
else else
return w_bits_msf(ob,num_bits,value); return w_bits_msf(ob,num_bits,value);
} }
/* ******************************************** */
/* CUSTOM STREAMFILES */
/* ******************************************** */
STREAMFILE* setup_subfile_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size, char* extension) {
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
new_streamFile = open_wrap_streamfile(streamFile);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
new_streamFile = open_clamp_streamfile(temp_streamFile, subfile_offset,subfile_size);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
if (extension) {
new_streamFile = open_fakename_streamfile(temp_streamFile, NULL,extension);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
}
return temp_streamFile;
fail:
close_streamfile(temp_streamFile);
return NULL;
}

View File

@ -1073,6 +1073,10 @@
<File <File
RelativePath=".\meta\msb_msh.c" RelativePath=".\meta\msb_msh.c"
> >
</File>
<File
RelativePath=".\meta\msf_banpresto.c"
>
</File> </File>
<File <File
RelativePath=".\meta\mss.c" RelativePath=".\meta\mss.c"

View File

@ -154,6 +154,7 @@
<ClCompile Include="meta\mogg.c" /> <ClCompile Include="meta\mogg.c" />
<ClCompile Include="meta\mp4.c" /> <ClCompile Include="meta\mp4.c" />
<ClCompile Include="meta\msb_msh.c" /> <ClCompile Include="meta\msb_msh.c" />
<ClCompile Include="meta\msf_banpresto.c" />
<ClCompile Include="meta\ngca.c" /> <ClCompile Include="meta\ngca.c" />
<ClCompile Include="meta\opus.c" /> <ClCompile Include="meta\opus.c" />
<ClCompile Include="meta\nub_vag.c" /> <ClCompile Include="meta\nub_vag.c" />

View File

@ -1390,6 +1390,9 @@
<ClCompile Include="meta\msb_msh.c"> <ClCompile Include="meta\msb_msh.c">
<Filter>meta\Source Files</Filter> <Filter>meta\Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="meta\msf_banpresto.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\mp4_aac_decoder.c"> <ClCompile Include="coding\mp4_aac_decoder.c">
<Filter>coding\Source Files</Filter> <Filter>coding\Source Files</Filter>
</ClCompile> </ClCompile>

View File

@ -801,4 +801,7 @@ VGMSTREAM * init_vgmstream_xopus(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_vs_ffx(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_vs_ffx(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_msf_banpresto_wmsf(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_msf_banpresto_2msf(STREAMFILE * streamFile);
#endif /*_META_H*/ #endif /*_META_H*/

62
src/meta/msf_banpresto.c Normal file
View File

@ -0,0 +1,62 @@
#include "meta.h"
#include "../coding/coding.h"
/* WMSF - Banpresto MSFx wrapper [Dai-2-Ji Super Robot Taisen OG: The Moon Dwellers (PS3)] */
VGMSTREAM * init_vgmstream_msf_banpresto_wmsf(STREAMFILE *streamFile) {
VGMSTREAM *vgmstream = NULL;
STREAMFILE *temp_streamFile = NULL;
off_t subfile_offset = 0x10;
size_t subfile_size = get_streamfile_size(streamFile) - subfile_offset;
/* checks */
if ( !check_extensions(streamFile,"msf"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x574D5346) /* "WMSF" */
goto fail;
/* 0x04: size, 0x08: flags? 0x0c: null? */
temp_streamFile = setup_subfile_streamfile(streamFile, subfile_offset,subfile_size, NULL);
if (!temp_streamFile) goto fail;
vgmstream = init_vgmstream_ps3_msf(temp_streamFile);
if (!vgmstream) goto fail;
close_streamfile(temp_streamFile);
return vgmstream;
fail:
close_streamfile(temp_streamFile);
close_vgmstream(vgmstream);
return NULL;
}
/* 2MSF - Banpresto RIFF wrapper [Dai-2-Ji Super Robot Taisen OG: The Moon Dwellers (PS4)] */
VGMSTREAM * init_vgmstream_msf_banpresto_2msf(STREAMFILE *streamFile) {
VGMSTREAM *vgmstream = NULL;
STREAMFILE *temp_streamFile = NULL;
off_t subfile_offset = 0x14;
size_t subfile_size = get_streamfile_size(streamFile) - subfile_offset;
/* checks */
if ( !check_extensions(streamFile,"at9"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x324D5346) /* "2MSF" */
goto fail;
/* 0x04: size, 0x08: flags? 0x0c: null?, 0x10: 0x01? (BE values even though RIFF is LE) */
temp_streamFile = setup_subfile_streamfile(streamFile, subfile_offset,subfile_size, NULL);
if (!temp_streamFile) goto fail;
vgmstream = init_vgmstream_riff(temp_streamFile);
if (!vgmstream) goto fail;
close_streamfile(temp_streamFile);
return vgmstream;
fail:
close_streamfile(temp_streamFile);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -4,32 +4,30 @@
/* MSF - Sony's PS3 SDK format (MultiStream File) */ /* MSF - Sony's PS3 SDK format (MultiStream File) */
VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) { VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL; VGMSTREAM * vgmstream = NULL;
off_t start_offset, header_offset = 0; off_t start_offset;
uint32_t data_size, loop_start = 0, loop_end = 0; uint32_t data_size, loop_start = 0, loop_end = 0;
uint32_t id, codec_id, flags; uint32_t id, codec_id, flags;
int loop_flag = 0, channel_count; int loop_flag = 0, channel_count;
/* checks */ /* checks */
/* .msf: standard, .at3: Silent Hill HD Collection, .mp3: Darkstalkers Resurrection */ /* .msf: standard
* .at3: Silent Hill HD Collection (PS3)
* .mp3: Darkstalkers Resurrection (PS3) */
if (!check_extensions(streamFile,"msf,at3,mp3")) if (!check_extensions(streamFile,"msf,at3,mp3"))
goto fail; goto fail;
/* "WMSF" variation with a mini header over the MSFC header [Dai-2-Ji Super Robot Generations (PS3)] */ start_offset = 0x40;
if (read_32bitBE(0x00,streamFile) == 0x574D5346) {
header_offset = 0x10;
}
start_offset = header_offset+0x40; /* MSF header is always 0x40 */
/* check header "MSF" + version-char /* check header "MSF" + version-char, usually:
* usually "MSF\0\1", "MSF\0\2", "MSF0"(\3\0), "MSF5"(\3\5), "MSFC"(\4\3) (last/common version) */ * 0x01, 0x02, 0x30 ("0"), 0x35 ("5"), 0x43 ("C") (last/most common version) */
id = read_32bitBE(header_offset+0x00,streamFile); id = read_32bitBE(0x00,streamFile);
if ((id & 0xffffff00) != 0x4D534600) goto fail; if ((id & 0xffffff00) != 0x4D534600) goto fail;
codec_id = read_32bitBE(header_offset+0x04,streamFile); codec_id = read_32bitBE(0x04,streamFile);
channel_count = read_32bitBE(header_offset+0x08,streamFile); channel_count = read_32bitBE(0x08,streamFile);
data_size = read_32bitBE(header_offset+0x0C,streamFile); /* without header */ data_size = read_32bitBE(0x0C,streamFile); /* without header */
if (data_size == 0xFFFFFFFF) /* unneeded? */ if (data_size == 0xFFFFFFFF) /* unneeded? */
data_size = get_streamfile_size(streamFile) - start_offset; data_size = get_streamfile_size(streamFile) - start_offset;
@ -39,15 +37,15 @@ VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) {
* 0x20: VBR MP3 source (changed into simplified 0x1a1 CBR) * 0x20: VBR MP3 source (changed into simplified 0x1a1 CBR)
* 0x40: joint stereo MP3 (apparently interleaved stereo for other formats) * 0x40: joint stereo MP3 (apparently interleaved stereo for other formats)
* 0x80+: (none/reserved) */ * 0x80+: (none/reserved) */
flags = read_32bitBE(header_offset+0x14,streamFile); flags = read_32bitBE(0x14,streamFile);
/* sometimes loop_start/end is set with flag 0x10, but from tests it only loops if 0x01/02 is set /* sometimes loop_start/end is set with flag 0x10, but from tests it only loops if 0x01/02 is set
* 0x10 often goes with 0x01 but not always (Castlevania HoD); Malicious PS3 uses flag 0x2 instead */ * 0x10 often goes with 0x01 but not always (Castlevania HoD); Malicious PS3 uses flag 0x2 instead */
loop_flag = flags != 0xffffffff && ((flags & 0x01) || (flags & 0x02)); loop_flag = flags != 0xffffffff && ((flags & 0x01) || (flags & 0x02));
/* loop markers (marker N @ 0x18 + N*(4+4), but in practice only marker 0 is used) */ /* loop markers (marker N @ 0x18 + N*(4+4), but in practice only marker 0 is used) */
if (loop_flag) { if (loop_flag) {
loop_start = read_32bitBE(header_offset+0x18,streamFile); loop_start = read_32bitBE(0x18,streamFile);
loop_end = read_32bitBE(header_offset+0x1C,streamFile); /* loop duration */ loop_end = read_32bitBE(0x1C,streamFile); /* loop duration */
loop_end = loop_start + loop_end; /* usually equals data_size but not always */ loop_end = loop_start + loop_end; /* usually equals data_size but not always */
if (loop_end > data_size)/* not seen */ if (loop_end > data_size)/* not seen */
loop_end = data_size; loop_end = data_size;
@ -58,9 +56,9 @@ VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) {
vgmstream = allocate_vgmstream(channel_count,loop_flag); vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail; if (!vgmstream) goto fail;
/* sample rate hack for strange MSFv1 files that don't have it */ vgmstream->sample_rate = read_32bitBE(0x10,streamFile);
vgmstream->sample_rate = read_32bitBE(header_offset+0x10,streamFile); /* sample rate hack for strange MSFv1 files (PS ADPCM only?) */
if (vgmstream->sample_rate == 0x00000000) /* PS ADPCM only? */ if (vgmstream->sample_rate == 0x00000000)
vgmstream->sample_rate = 48000; vgmstream->sample_rate = 48000;
vgmstream->meta_type = meta_PS3_MSF; vgmstream->meta_type = meta_PS3_MSF;
@ -116,11 +114,9 @@ VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) {
encoder_delay = 1162; encoder_delay = 1162;
vgmstream->num_samples = atrac3_bytes_to_samples(data_size, block_size) - encoder_delay; vgmstream->num_samples = atrac3_bytes_to_samples(data_size, block_size) - encoder_delay;
if (vgmstream->sample_rate == 0xFFFFFFFF) /* some MSFv1 (Digi World SP) */ if (vgmstream->sample_rate == 0xFFFFFFFF) /* some MSFv1 (Digi World SP) */
vgmstream->sample_rate = 44100;//voice tracks seems to use 44khz, not sure about other tracks vgmstream->sample_rate = 44100; /* voice tracks seems to use 44khz, not sure about other tracks */
bytes = ffmpeg_make_riff_atrac3(buf, 100, vgmstream->num_samples, data_size, vgmstream->channels, vgmstream->sample_rate, block_size, joint_stereo, encoder_delay); bytes = ffmpeg_make_riff_atrac3(buf, 100, vgmstream->num_samples, data_size, vgmstream->channels, vgmstream->sample_rate, block_size, joint_stereo, encoder_delay);
if (bytes <= 0) goto fail;
ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,data_size); ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,data_size);
if (!ffmpeg_data) goto fail; if (!ffmpeg_data) goto fail;
vgmstream->codec_data = ffmpeg_data; vgmstream->codec_data = ffmpeg_data;
@ -156,7 +152,7 @@ VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) {
if (loop_flag) { if (loop_flag) {
vgmstream->loop_start_sample = (int64_t)loop_start * ffmpeg_data->sampleRate * 8 / ffmpeg_data->bitrate; vgmstream->loop_start_sample = (int64_t)loop_start * ffmpeg_data->sampleRate * 8 / ffmpeg_data->bitrate;
vgmstream->loop_end_sample = (int64_t)loop_end * ffmpeg_data->sampleRate * 8 / ffmpeg_data->bitrate; vgmstream->loop_end_sample = (int64_t)loop_end * ffmpeg_data->sampleRate * 8 / ffmpeg_data->bitrate;
/* loops are always CBR frame beginnings */ /* loops are always aligned to CBR frame beginnings */
} }
/* encoder delay varies between 1152 (1f), 528, 576, etc; probably not actually skipped */ /* encoder delay varies between 1152 (1f), 528, 576, etc; probably not actually skipped */
@ -164,7 +160,7 @@ VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) {
} }
#endif #endif
#ifdef VGM_USE_MPEG #ifdef VGM_USE_MPEG
case 0x07: { /* MPEG (CBR LAME MP3) []Dengeki Bunko Fighting Climax (PS3) */ case 0x07: { /* MPEG (CBR LAME MP3) [Dengeki Bunko Fighting Climax (PS3)] */
mpeg_codec_data *mpeg_data = NULL; mpeg_codec_data *mpeg_data = NULL;
mpeg_data = init_mpeg(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels); mpeg_data = init_mpeg(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels);
@ -176,7 +172,7 @@ VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) {
if (loop_flag) { if (loop_flag) {
vgmstream->loop_start_sample = mpeg_bytes_to_samples(loop_start, mpeg_data); vgmstream->loop_start_sample = mpeg_bytes_to_samples(loop_start, mpeg_data);
vgmstream->loop_end_sample = mpeg_bytes_to_samples(loop_end, mpeg_data); vgmstream->loop_end_sample = mpeg_bytes_to_samples(loop_end, mpeg_data);
/* loops are always CBR frame beginnings */ /* loops are always aligned to CBR frame beginnings */
} }
/* encoder delay varies between 1152 (1f), 528, 576, etc; probably not actually skipped */ /* encoder delay varies between 1152 (1f), 528, 576, etc; probably not actually skipped */

View File

@ -445,6 +445,8 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_xwma, init_vgmstream_xwma,
init_vgmstream_xopus, init_vgmstream_xopus,
init_vgmstream_vs_ffx, init_vgmstream_vs_ffx,
init_vgmstream_msf_banpresto_wmsf,
init_vgmstream_msf_banpresto_2msf,
/* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */ /* 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 */ init_vgmstream_txth, /* proper parsers should supersede TXTH, once added */