mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-24 23:10:10 +01:00
commit
8bbe52bb9a
@ -352,4 +352,8 @@ typedef struct {
|
||||
int r_bits(vgm_bitstream * ib, 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, const char* extension);
|
||||
|
||||
#endif /*_CODING_H*/
|
||||
|
@ -1080,3 +1080,31 @@ int w_bits(vgm_bitstream * ob, int num_bits, uint32_t value) {
|
||||
else
|
||||
return w_bits_msf(ob,num_bits,value);
|
||||
}
|
||||
|
||||
/* ******************************************** */
|
||||
/* CUSTOM STREAMFILES */
|
||||
/* ******************************************** */
|
||||
|
||||
STREAMFILE* setup_subfile_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size, const 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;
|
||||
}
|
||||
|
@ -686,7 +686,7 @@ static const layout_info layout_info_list[] = {
|
||||
{layout_blocked_sthd, "blocked (STHD)"},
|
||||
{layout_blocked_h4m, "blocked (H4M)"},
|
||||
{layout_blocked_xa_aiff, "blocked (XA AIFF)"},
|
||||
{layout_blocked_vs_ffx, "blocked (Final Fantasy X VS)"},
|
||||
{layout_blocked_vs_ffx, "blocked (Square VS)"},
|
||||
};
|
||||
|
||||
static const meta_info meta_info_list[] = {
|
||||
@ -758,7 +758,7 @@ static const meta_info meta_info_list[] = {
|
||||
{meta_WS_AUD, "Westwood Studios .aud header"},
|
||||
{meta_WS_AUD_old, "Westwood Studios .aud (old) header"},
|
||||
{meta_PS2_IVB, "IVB/BVII header"},
|
||||
{meta_PS2_SVS, "Square SVS header"},
|
||||
{meta_SVS, "Square SVS header"},
|
||||
{meta_RIFF_WAVE, "RIFF WAVE header"},
|
||||
{meta_RIFF_WAVE_POS, "RIFF WAVE header and .pos for looping"},
|
||||
{meta_NWA, "VisualArt's NWA header"},
|
||||
@ -853,8 +853,7 @@ static const meta_info meta_info_list[] = {
|
||||
{meta_IDSP_NL, "Next Level IDSP header"},
|
||||
{meta_IDSP_IE, "Inevitable Entertainment IDSP Header"},
|
||||
{meta_UBI_JADE, "Ubisoft Jade RIFF header"},
|
||||
{meta_PS2_SEG, "SEG (PS2) Header"},
|
||||
{meta_XBOX_SEG, "SEG (XBOX) Header"},
|
||||
{meta_SEG, "Stormfront SEG header"},
|
||||
{meta_NDS_STRM_FFTA2, "Final Fantasy Tactics A2 RIFF Header"},
|
||||
{meta_STR_ASR, "Donkey Kong Jet Race KNON/WII Header"},
|
||||
{meta_ZWDSP, "Zack and Wiki custom DSP Header"},
|
||||
@ -1107,7 +1106,7 @@ static const meta_info meta_info_list[] = {
|
||||
{meta_XWMA, "Microsoft XWMA RIFF header"},
|
||||
{meta_VA3, "Konami VA3 header" },
|
||||
{meta_XOPUS, "Exient XOPUS header"},
|
||||
{meta_VS_FFX, "Final Fantasy X VS header"},
|
||||
{meta_VS_FFX, "Square VS header"},
|
||||
|
||||
};
|
||||
|
||||
|
@ -1,24 +1,15 @@
|
||||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* Final Fantasy X VS headered blocks */
|
||||
/* Square "VS" headered blocks */
|
||||
void block_update_vs_ffx(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i;
|
||||
size_t block_size = 0x800;
|
||||
|
||||
/* 0x00: header id
|
||||
* 0x04: null
|
||||
* 0x08: block number
|
||||
* 0x0c: blocks left in the subfile
|
||||
* 0x10: always 0x1000
|
||||
* 0x14: always 0x64
|
||||
* 0x18: null
|
||||
* 0x1c: null */
|
||||
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->current_block_size = block_size - 0x20;
|
||||
vgmstream->next_block_offset = block_offset + block_size;
|
||||
/* 0x08: number of remaning blocks, 0x10: some id/size? (shared in all blocks) */
|
||||
/* 0x08: number of remaning blocks, 0x0c: blocks left */
|
||||
|
||||
for (i = 0; i < vgmstream->channels; i++) {
|
||||
vgmstream->ch[i].offset = block_offset + 0x20 + 0x800*i;
|
||||
|
@ -1073,6 +1073,10 @@
|
||||
<File
|
||||
RelativePath=".\meta\msb_msh.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\msf_banpresto.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\mss.c"
|
||||
|
@ -154,6 +154,7 @@
|
||||
<ClCompile Include="meta\mogg.c" />
|
||||
<ClCompile Include="meta\mp4.c" />
|
||||
<ClCompile Include="meta\msb_msh.c" />
|
||||
<ClCompile Include="meta\msf_banpresto.c" />
|
||||
<ClCompile Include="meta\ngca.c" />
|
||||
<ClCompile Include="meta\opus.c" />
|
||||
<ClCompile Include="meta\nub_vag.c" />
|
||||
|
@ -1390,6 +1390,9 @@
|
||||
<ClCompile Include="meta\msb_msh.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\msf_banpresto.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="coding\mp4_aac_decoder.c">
|
||||
<Filter>coding\Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
@ -3,8 +3,6 @@
|
||||
#include "../coding/coding.h"
|
||||
#include "aax_utf.h"
|
||||
|
||||
static STREAMFILE* setup_aax_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size, const char* fake_ext);
|
||||
|
||||
|
||||
#define MAX_SEGMENTS 2 /* usually segment0=intro, segment1=loop/main */
|
||||
|
||||
@ -77,7 +75,7 @@ VGMSTREAM * init_vgmstream_aax(STREAMFILE *streamFile) {
|
||||
|
||||
/* open each segment subfile */
|
||||
for (i = 0; i < segment_count; i++) {
|
||||
STREAMFILE* temp_streamFile = setup_aax_streamfile(streamFile, segment_offset[i],segment_size[i], (is_hca ? "hca" : "adx"));
|
||||
STREAMFILE* temp_streamFile = setup_subfile_streamfile(streamFile, segment_offset[i],segment_size[i], (is_hca ? "hca" : "adx"));
|
||||
if (!temp_streamFile) goto fail;
|
||||
|
||||
data->segments[i] = is_hca ?
|
||||
@ -138,29 +136,6 @@ fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static STREAMFILE* setup_aax_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size, const char* fake_ext) {
|
||||
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||
|
||||
/* setup subfile */
|
||||
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;
|
||||
|
||||
new_streamFile = open_fakename_streamfile(temp_streamFile, NULL,fake_ext);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
return temp_streamFile;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* CRI's UTF wrapper around DSP [Sonic Colors sfx (Wii), NiGHTS: Journey of Dreams sfx (Wii)] */
|
||||
VGMSTREAM * init_vgmstream_utf_dsp(STREAMFILE *streamFile) {
|
||||
|
@ -1,7 +1,6 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
static STREAMFILE* setup_atsl_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size, const char* fake_ext);
|
||||
typedef enum { ATRAC3, ATRAC9, KOVS, KTSS } atsl_codec;
|
||||
|
||||
/* .ATSL - Koei Tecmo audio container [One Piece Pirate Warriors (PS3), Warriors All-Stars (PC)] */
|
||||
@ -110,7 +109,7 @@ VGMSTREAM * init_vgmstream_atsl(STREAMFILE *streamFile) {
|
||||
/* some kind of seek/switch table may follow (optional, found in .atsl3) */
|
||||
|
||||
|
||||
temp_streamFile = setup_atsl_streamfile(streamFile, subfile_offset,subfile_size, fake_ext);
|
||||
temp_streamFile = setup_subfile_streamfile(streamFile, subfile_offset,subfile_size, fake_ext);
|
||||
if (!temp_streamFile) goto fail;
|
||||
|
||||
/* init the VGMSTREAM */
|
||||
@ -144,27 +143,3 @@ fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static STREAMFILE* setup_atsl_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size, const char* fake_ext) {
|
||||
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||
|
||||
/* setup subfile */
|
||||
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;
|
||||
|
||||
new_streamFile = open_fakename_streamfile(temp_streamFile, NULL,fake_ext);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
return temp_streamFile;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -801,4 +801,7 @@ VGMSTREAM * init_vgmstream_xopus(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*/
|
||||
|
62
src/meta/msf_banpresto.c
Normal file
62
src/meta/msf_banpresto.c
Normal 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;
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* SPSD - Naomi (arcade) streams [Guilty Gear X (Naomi), Crazy Taxi (Naomi), Virtua Tennis 2 (Naomi)] */
|
||||
/* SPSD - Naomi (arcade) and early Dreamcast streams [Guilty Gear X (Naomi), Crazy Taxi (Naomi), Virtua Tennis 2 (Naomi)] */
|
||||
VGMSTREAM * init_vgmstream_naomi_spsd(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
@ -10,8 +10,9 @@ VGMSTREAM * init_vgmstream_naomi_spsd(STREAMFILE *streamFile) {
|
||||
|
||||
|
||||
/* checks */
|
||||
/* .spsd: header id */
|
||||
if (!check_extensions(streamFile, "spsd"))
|
||||
/* .str: actual extension, rare [Shenmue (DC)]
|
||||
* .spsd: header id */
|
||||
if (!check_extensions(streamFile, "str,spsd"))
|
||||
goto fail;
|
||||
if (read_32bitBE(0x00,streamFile) != 0x53505344) /* "SPSD" */
|
||||
goto fail;
|
||||
|
@ -9,30 +9,30 @@ VGMSTREAM * init_vgmstream_ngc_dsp_mpds(STREAMFILE *streamFile) {
|
||||
int loop_flag = 0, channel_count, short_mpds;
|
||||
|
||||
|
||||
/* check extension, case insensitive */
|
||||
/* checks */
|
||||
/* .dsp: Big Air Freestyle */
|
||||
/* .mds: Terminator 3 The Redemption, Mission Impossible: Operation Surma */
|
||||
if (!check_extensions(streamFile, "dsp,mds")) goto fail;
|
||||
|
||||
/* check header */
|
||||
if (!check_extensions(streamFile, "dsp,mds"))
|
||||
goto fail;
|
||||
if (read_32bitBE(0x00,streamFile) != 0x4D504453) /* "MPDS" */
|
||||
goto fail;
|
||||
|
||||
short_mpds = read_32bitBE(0x04,streamFile) != 0x00010000 && check_extensions(streamFile, "mds"); /* version byte? */
|
||||
short_mpds = read_32bitBE(0x04,streamFile) != 0x00010000 && /* version byte? */
|
||||
check_extensions(streamFile, "mds");
|
||||
|
||||
channel_count = short_mpds ?
|
||||
read_16bitBE(0x0a, streamFile) :
|
||||
read_32bitBE(0x14, streamFile);
|
||||
if (channel_count > 2) goto fail;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->meta_type = meta_NGC_DSP_MPDS;
|
||||
vgmstream->layout_type = channel_count == 1 ? layout_none : layout_interleave;
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
|
||||
if (!short_mpds) { /* Big Air Freestyle */
|
||||
start_offset = 0x80;
|
||||
@ -50,17 +50,22 @@ VGMSTREAM * init_vgmstream_ngc_dsp_mpds(STREAMFILE *streamFile) {
|
||||
vgmstream->num_samples = read_32bitBE(0x04,streamFile);
|
||||
vgmstream->sample_rate = (uint16_t)read_16bitBE(0x08,streamFile);
|
||||
vgmstream->interleave_block_size = channel_count==1 ? 0 : 0x200;
|
||||
/* some kind of hist after 0x0c? */
|
||||
|
||||
#if 0 //unknown coeffs/hist, related to data after 0x0c? (only coefs 0..7 seem to be needed)
|
||||
/* set coefs, debugged from the MI:OS ELF (helpfully marked as "sMdsCoefs") */
|
||||
{
|
||||
off_t offset = 0x0c;
|
||||
int i,ch;
|
||||
for (ch=0; ch < vgmstream->channels; ch++) {
|
||||
for (i=0; i < 16; i++)
|
||||
vgmstream->ch[ch].adpcm_coef[i] = read_16bitBE(offset + i*2);
|
||||
static const int16_t coefs[16] = {
|
||||
0x0000,0x0000,0x0780,0x0000,0x0e60,0xf980,0x0c40,0xf920,
|
||||
0x0f40,0xf880,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
|
||||
};
|
||||
int i, ch;
|
||||
|
||||
for (ch = 0; ch < channel_count; ch++) {
|
||||
for (i = 0; i < 16; i++) {
|
||||
vgmstream->ch[ch].adpcm_coef[i] = coefs[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
static STREAMFILE* setup_nus3bank_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size, const char* fake_ext);
|
||||
typedef enum { /*XMA_RAW, ATRAC3,*/ IDSP, ATRAC9, OPUS, BNSF, /*PCM, XMA_RIFF*/ } nus3bank_codec;
|
||||
|
||||
/* .nus3bank - Namco's newest audio container [Super Smash Bros (Wii U), idolmaster (PS4))] */
|
||||
@ -144,7 +143,7 @@ VGMSTREAM * init_vgmstream_nus3bank(STREAMFILE *streamFile) {
|
||||
|
||||
//;VGM_LOG("NUS3BANK: subfile=%lx, size=%x\n", subfile_offset, subfile_size);
|
||||
|
||||
temp_streamFile = setup_nus3bank_streamfile(streamFile, subfile_offset,subfile_size, fake_ext);
|
||||
temp_streamFile = setup_subfile_streamfile(streamFile, subfile_offset,subfile_size, fake_ext);
|
||||
if (!temp_streamFile) goto fail;
|
||||
|
||||
/* init the VGMSTREAM */
|
||||
@ -182,27 +181,3 @@ fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static STREAMFILE* setup_nus3bank_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size, const char* fake_ext) {
|
||||
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||
|
||||
/* setup subfile */
|
||||
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;
|
||||
|
||||
new_streamFile = open_fakename_streamfile(temp_streamFile, NULL,fake_ext);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
return temp_streamFile;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -2,8 +2,6 @@
|
||||
#include "../coding/coding.h"
|
||||
#include "../layout/layout.h"
|
||||
|
||||
static STREAMFILE* setup_opus_ppp_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size, const char* fake_ext);
|
||||
|
||||
/* Nippon Ichi SPS wrapper (segmented) [Penny-Punching Princess (Switch)] */
|
||||
VGMSTREAM * init_vgmstream_opus_sps_n1_segmented(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
@ -43,7 +41,7 @@ VGMSTREAM * init_vgmstream_opus_sps_n1_segmented(STREAMFILE *streamFile) {
|
||||
if (!segment_size)
|
||||
goto fail;
|
||||
|
||||
temp_streamFile = setup_opus_ppp_streamfile(streamFile, segment_offset,segment_size, "opus");
|
||||
temp_streamFile = setup_subfile_streamfile(streamFile, segment_offset,segment_size, "opus");
|
||||
if (!temp_streamFile) goto fail;
|
||||
|
||||
data->segments[i] = init_vgmstream_opus_std(temp_streamFile);
|
||||
@ -93,26 +91,3 @@ fail:
|
||||
free_layout_segmented(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static STREAMFILE* setup_opus_ppp_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size, const char* fake_ext) {
|
||||
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||
|
||||
/* setup subfile */
|
||||
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;
|
||||
|
||||
new_streamFile = open_fakename_streamfile(temp_streamFile, NULL,fake_ext);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
return temp_streamFile;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -313,8 +313,6 @@ fail:
|
||||
|
||||
/* ****************************************************************************** */
|
||||
|
||||
static STREAMFILE* setup_subfile_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size, const char* fake_ext);
|
||||
|
||||
/* ADS in containers */
|
||||
VGMSTREAM * init_vgmstream_ps2_ads_container(STREAMFILE *streamFile) {
|
||||
VGMSTREAM *vgmstream = NULL;
|
||||
@ -356,28 +354,3 @@ fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static STREAMFILE* setup_subfile_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size, const char* fake_ext) {
|
||||
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||
|
||||
/* setup subfile */
|
||||
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 (fake_ext) {
|
||||
new_streamFile = open_fakename_streamfile(temp_streamFile, NULL,fake_ext);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
}
|
||||
|
||||
return temp_streamFile;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1,15 +1,13 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* VA3 - Konami / Sont Atrac3 Container */
|
||||
|
||||
|
||||
/* PS2 DDR Supernova 2 Arcade */
|
||||
/* VA3 - Konami / Sony Atrac3 Container [PS2 DDR Supernova 2 Arcade] */
|
||||
VGMSTREAM * init_vgmstream_va3(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag, channel_count;
|
||||
uint32_t data_size, loop_start, loop_end, codec_id;
|
||||
uint32_t data_size, loop_start, loop_end;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
if (!check_extensions(streamFile, "va3"))
|
||||
|
@ -4,32 +4,30 @@
|
||||
/* MSF - Sony's PS3 SDK format (MultiStream File) */
|
||||
VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) {
|
||||
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 id, codec_id, flags;
|
||||
int loop_flag = 0, channel_count;
|
||||
|
||||
|
||||
/* 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"))
|
||||
goto fail;
|
||||
|
||||
/* "WMSF" variation with a mini header over the MSFC header [Dai-2-Ji Super Robot Generations (PS3)] */
|
||||
if (read_32bitBE(0x00,streamFile) == 0x574D5346) {
|
||||
header_offset = 0x10;
|
||||
}
|
||||
start_offset = header_offset+0x40; /* MSF header is always 0x40 */
|
||||
start_offset = 0x40;
|
||||
|
||||
/* check header "MSF" + version-char
|
||||
* usually "MSF\0\1", "MSF\0\2", "MSF0"(\3\0), "MSF5"(\3\5), "MSFC"(\4\3) (last/common version) */
|
||||
id = read_32bitBE(header_offset+0x00,streamFile);
|
||||
/* check header "MSF" + version-char, usually:
|
||||
* 0x01, 0x02, 0x30 ("0"), 0x35 ("5"), 0x43 ("C") (last/most common version) */
|
||||
id = read_32bitBE(0x00,streamFile);
|
||||
if ((id & 0xffffff00) != 0x4D534600) goto fail;
|
||||
|
||||
|
||||
codec_id = read_32bitBE(header_offset+0x04,streamFile);
|
||||
channel_count = read_32bitBE(header_offset+0x08,streamFile);
|
||||
data_size = read_32bitBE(header_offset+0x0C,streamFile); /* without header */
|
||||
codec_id = read_32bitBE(0x04,streamFile);
|
||||
channel_count = read_32bitBE(0x08,streamFile);
|
||||
data_size = read_32bitBE(0x0C,streamFile); /* without header */
|
||||
if (data_size == 0xFFFFFFFF) /* unneeded? */
|
||||
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)
|
||||
* 0x40: joint stereo MP3 (apparently interleaved stereo for other formats)
|
||||
* 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
|
||||
* 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 markers (marker N @ 0x18 + N*(4+4), but in practice only marker 0 is used) */
|
||||
if (loop_flag) {
|
||||
loop_start = read_32bitBE(header_offset+0x18,streamFile);
|
||||
loop_end = read_32bitBE(header_offset+0x1C,streamFile); /* loop duration */
|
||||
loop_start = read_32bitBE(0x18,streamFile);
|
||||
loop_end = read_32bitBE(0x1C,streamFile); /* loop duration */
|
||||
loop_end = loop_start + loop_end; /* usually equals data_size but not always */
|
||||
if (loop_end > data_size)/* not seen */
|
||||
loop_end = data_size;
|
||||
@ -58,9 +56,9 @@ VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) {
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* sample rate hack for strange MSFv1 files that don't have it */
|
||||
vgmstream->sample_rate = read_32bitBE(header_offset+0x10,streamFile);
|
||||
if (vgmstream->sample_rate == 0x00000000) /* PS ADPCM only? */
|
||||
vgmstream->sample_rate = read_32bitBE(0x10,streamFile);
|
||||
/* sample rate hack for strange MSFv1 files (PS ADPCM only?) */
|
||||
if (vgmstream->sample_rate == 0x00000000)
|
||||
vgmstream->sample_rate = 48000;
|
||||
|
||||
vgmstream->meta_type = meta_PS3_MSF;
|
||||
@ -115,12 +113,10 @@ VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) {
|
||||
* (note that encoder may add a fade-in with looping/resampling enabled but should be skipped) */
|
||||
encoder_delay = 1162;
|
||||
vgmstream->num_samples = atrac3_bytes_to_samples(data_size, block_size) - encoder_delay;
|
||||
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
|
||||
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 */
|
||||
|
||||
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);
|
||||
if (!ffmpeg_data) goto fail;
|
||||
vgmstream->codec_data = ffmpeg_data;
|
||||
@ -156,7 +152,7 @@ VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) {
|
||||
if (loop_flag) {
|
||||
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;
|
||||
/* 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 */
|
||||
@ -164,7 +160,7 @@ VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) {
|
||||
}
|
||||
#endif
|
||||
#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_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) {
|
||||
vgmstream->loop_start_sample = mpeg_bytes_to_samples(loop_start, 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 */
|
||||
|
144
src/meta/seg.c
144
src/meta/seg.c
@ -1,94 +1,110 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
|
||||
/* SEG - found in Eragon */
|
||||
/* SEG - from Stormfront games [Eragon (multi), Forgotten Realms: Demon Stone (multi) */
|
||||
VGMSTREAM * init_vgmstream_seg(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
off_t start_offset;
|
||||
int loop_flag;
|
||||
int channel_count;
|
||||
coding_t coding;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("seg",filename_extension(filename))) goto fail;
|
||||
int loop_flag, channel_count;
|
||||
size_t data_size;
|
||||
uint32_t codec;
|
||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
|
||||
|
||||
|
||||
/* check header */
|
||||
if (read_32bitBE(0x00,streamFile) != 0x73656700) /* "seg\0" */
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "seg"))
|
||||
goto fail;
|
||||
if (read_32bitBE(0x00,streamFile) != 0x73656700) /* "seg\0" */
|
||||
goto fail;
|
||||
if (read_32bitBE(0x04,streamFile) == 0x70733200) /* "ps2\0" */
|
||||
{
|
||||
coding = coding_PSX;
|
||||
}
|
||||
else if (read_32bitBE(0x04,streamFile) == 0x78627800) /* "xbx\0" */
|
||||
{
|
||||
coding = coding_XBOX_IMA;
|
||||
}
|
||||
else goto fail;
|
||||
|
||||
loop_flag = 0;
|
||||
channel_count = read_32bitLE(0x24,streamFile);
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
codec = read_32bitBE(0x04,streamFile);
|
||||
/* 0x08: version? (2: Eragon, Spiderwick Chronicles Wii / 3: Spiderwick Chronicles X360 / 4: Spiderwick Chronicles PC) */
|
||||
if (guess_endianness32bit(0x08,streamFile)) {
|
||||
read_32bit = read_32bitBE;
|
||||
} else {
|
||||
read_32bit = read_32bitLE;
|
||||
}
|
||||
/* 0x0c: file size */
|
||||
data_size = read_32bit(0x10, streamFile); /* including interleave padding */
|
||||
/* 0x14: null */
|
||||
|
||||
loop_flag = read_32bit(0x20,streamFile); /* rare */
|
||||
channel_count = read_32bit(0x24,streamFile);
|
||||
/* 0x28: extradata 1 entries (0x08 per entry, unknown) */
|
||||
/* 0x2c: extradata 1 offset */
|
||||
/* 0x30: extradata 2 entries (0x10 or 0x14 per entry, seek/hist table?) */
|
||||
/* 0x34: extradata 2 offset */
|
||||
|
||||
start_offset = 0x4000;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
start_offset = 0x4000;
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = read_32bitLE(0x18,streamFile);
|
||||
vgmstream->coding_type = coding;
|
||||
|
||||
vgmstream->meta_type = meta_SEG;
|
||||
vgmstream->sample_rate = read_32bit(0x18,streamFile);
|
||||
vgmstream->num_samples = read_32bit(0x1c,streamFile);
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = read_32bitLE(0x1C,streamFile);
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
}
|
||||
read_string(vgmstream->stream_name,0x20+1, 0x38,streamFile);
|
||||
|
||||
vgmstream->interleave_block_size = 0;
|
||||
switch(codec) {
|
||||
case 0x70733200: /* "ps2\0" */
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x2000;
|
||||
break;
|
||||
|
||||
if (coding_PSX == coding)
|
||||
{
|
||||
vgmstream->num_samples = (read_32bitLE(0x0C,streamFile)-start_offset)*28/16/channel_count;
|
||||
vgmstream->meta_type = meta_PS2_SEG;
|
||||
case 0x78627800: /* "xbx\0" */
|
||||
vgmstream->coding_type = coding_XBOX_IMA;
|
||||
vgmstream->layout_type = layout_none;
|
||||
break;
|
||||
|
||||
if (channel_count == 1) {
|
||||
vgmstream->layout_type = layout_none;
|
||||
} else if (channel_count == 2) {
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x2000;
|
||||
}
|
||||
}
|
||||
else if (coding_XBOX_IMA == coding)
|
||||
{
|
||||
vgmstream->num_samples = xbox_ima_bytes_to_samples(read_32bitLE(0x0C,streamFile)-start_offset, channel_count);
|
||||
vgmstream->meta_type = meta_XBOX_SEG;
|
||||
vgmstream->layout_type = layout_none;
|
||||
}
|
||||
else goto fail;
|
||||
case 0x77696900: /* "wii\0" */
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x2000;
|
||||
|
||||
/* open the file for reading */
|
||||
{
|
||||
int i;
|
||||
STREAMFILE * file;
|
||||
file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!file) goto fail;
|
||||
for (i=0;i<channel_count;i++) {
|
||||
vgmstream->ch[i].streamfile = file;
|
||||
/* standard dsp header at start_offset */
|
||||
dsp_read_coefs_be(vgmstream, streamFile, start_offset+0x1c, vgmstream->interleave_block_size);
|
||||
dsp_read_hist_be(vgmstream, streamFile, start_offset+0x40, vgmstream->interleave_block_size);
|
||||
//todo first_interleave: 0x2000 - 60
|
||||
break;
|
||||
|
||||
vgmstream->ch[i].channel_start_offset=
|
||||
vgmstream->ch[i].offset=start_offset+
|
||||
vgmstream->interleave_block_size*i;
|
||||
case 0x70635F00: /* "pc_\0" */
|
||||
vgmstream->coding_type = coding_IMA;
|
||||
vgmstream->layout_type = layout_none;
|
||||
break;
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
case 0x78623300: { /* "xb3\0" */
|
||||
uint8_t buf[0x100];
|
||||
int bytes, block_size, block_count;
|
||||
|
||||
block_size = 0x4000;
|
||||
block_count = data_size / block_size + (data_size % block_size ? 1 : 0);
|
||||
|
||||
bytes = ffmpeg_make_riff_xma2(buf,0x100, vgmstream->num_samples, data_size, vgmstream->channels, vgmstream->sample_rate, block_count, block_size);
|
||||
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,data_size);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1,8 +1,6 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
static STREAMFILE* setup_sps_streamfile(STREAMFILE *streamfile, off_t subfile_offset, size_t subfile_size, char* extension);
|
||||
|
||||
/* .SPS - Nippon Ichi wrapper [ClaDun (PSP)] */
|
||||
VGMSTREAM * init_vgmstream_sps_n1(STREAMFILE *streamFile) {
|
||||
VGMSTREAM *vgmstream = NULL;
|
||||
@ -26,7 +24,7 @@ VGMSTREAM * init_vgmstream_sps_n1(STREAMFILE *streamFile) {
|
||||
/* init the VGMSTREAM */
|
||||
switch(type) {
|
||||
case 1: /* .vag */
|
||||
temp_streamFile = setup_sps_streamfile(streamFile, subfile_offset, subfile_size, "vag");
|
||||
temp_streamFile = setup_subfile_streamfile(streamFile, subfile_offset, subfile_size, "vag");
|
||||
if (!temp_streamFile) goto fail;
|
||||
|
||||
vgmstream = init_vgmstream_vag(temp_streamFile);
|
||||
@ -34,7 +32,7 @@ VGMSTREAM * init_vgmstream_sps_n1(STREAMFILE *streamFile) {
|
||||
break;
|
||||
|
||||
case 2: /* .at3 */
|
||||
temp_streamFile = setup_sps_streamfile(streamFile, subfile_offset, subfile_size, "at3");
|
||||
temp_streamFile = setup_subfile_streamfile(streamFile, subfile_offset, subfile_size, "at3");
|
||||
if (!temp_streamFile) goto fail;
|
||||
|
||||
vgmstream = init_vgmstream_riff(temp_streamFile);
|
||||
@ -54,26 +52,3 @@ fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static STREAMFILE* setup_sps_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size, char* extension) {
|
||||
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||
|
||||
/* setup subfile */
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -1,69 +1,54 @@
|
||||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* SVS (from Unlimited Saga) */
|
||||
/* probably Square Vag Stream */
|
||||
|
||||
/* SVS - SeqVagStream from Square games [Unlimited Saga (PS2) music] */
|
||||
VGMSTREAM * init_vgmstream_svs(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
off_t start_offset;
|
||||
int channel_count, loop_flag, pitch;
|
||||
|
||||
int loop_flag = 0;
|
||||
int channel_count;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("svs",filename_extension(filename))) goto fail;
|
||||
|
||||
/* check header */
|
||||
/* checks */
|
||||
/* .svs: header id (probably ok like The Bouncer's .vs) */
|
||||
if (!check_extensions(streamFile, "svs"))
|
||||
goto fail;
|
||||
if (read_32bitBE(0x00,streamFile) != 0x53565300) /* "SVS\0" */
|
||||
goto fail;
|
||||
|
||||
loop_flag = (read_32bitLE(0x08,streamFile)!=0);
|
||||
/* 63.SVS has start and end on the same sample, which crashes stuff */
|
||||
if (read_32bitLE(0x08,streamFile)==read_32bitLE(0x0c,streamFile))
|
||||
loop_flag = 0;
|
||||
/* 0x04: flags (1=stereo?, 2=loop) */
|
||||
pitch = read_32bitLE(0x10,streamFile); /* usually 0x1000 = 48000 */
|
||||
/* 0x14: volume? */
|
||||
/* 0x18: file id (may be null) */
|
||||
/* 0x1c: null */
|
||||
|
||||
loop_flag = (read_32bitLE(0x08,streamFile) > 0); /* loop start frame, min is 1 */
|
||||
channel_count = 2;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
start_offset = 0x20;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
start_offset = 0x40;
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = 44100;
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->num_samples = (get_streamfile_size(streamFile)-0x40)*28/16/channel_count;
|
||||
vgmstream->meta_type = meta_SVS;
|
||||
vgmstream->sample_rate = (48000 * pitch) / 4096; /* music = ~44100, ambience = 48000 */
|
||||
vgmstream->num_samples = ps_bytes_to_samples(get_streamfile_size(streamFile) - start_offset, channel_count);
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = (read_32bitLE(0x08,streamFile)-1)*28;
|
||||
vgmstream->loop_end_sample = (read_32bitLE(0x0c,streamFile)-1)*28;
|
||||
vgmstream->loop_start_sample = read_32bitLE(0x08,streamFile) * 28; /* frame count (0x10*ch) */
|
||||
vgmstream->loop_end_sample = read_32bitLE(0x0c,streamFile) * 28; /* frame count, (not exact num_samples when no loop) */
|
||||
/* start/end on the same frame rarely happens too (ex. file_id 63 SVS), perhaps loop should be +1 */
|
||||
}
|
||||
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x10;
|
||||
vgmstream->meta_type = meta_PS2_SVS;
|
||||
|
||||
/* open the file for reading */
|
||||
{
|
||||
int i;
|
||||
STREAMFILE * file;
|
||||
file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!file) goto fail;
|
||||
for (i=0;i<channel_count;i++) {
|
||||
vgmstream->ch[i].streamfile = file;
|
||||
|
||||
vgmstream->ch[i].channel_start_offset=
|
||||
vgmstream->ch[i].offset=start_offset+
|
||||
vgmstream->interleave_block_size*i;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
static STREAMFILE* setup_jade_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size, const char* fake_ext);
|
||||
static int get_loop_points(STREAMFILE *streamFile, int *out_loop_start, int *out_loop_end);
|
||||
|
||||
/* Jade RIFF - from Ubisoft Jade engine games [Beyond Good & Evil (multi), Rayman Raving Rabbids 1/2 (multi)] */
|
||||
@ -231,7 +230,7 @@ VGMSTREAM * init_vgmstream_ubi_jade(STREAMFILE *streamFile) {
|
||||
if (read_32bitBE(start_offset, streamFile) != 0x4D534643) /* "MSF\43" */
|
||||
goto fail;
|
||||
|
||||
temp_streamFile = setup_jade_streamfile(streamFile, start_offset, data_size, "msf");
|
||||
temp_streamFile = setup_subfile_streamfile(streamFile, start_offset, data_size, "msf");
|
||||
if (!temp_streamFile) goto fail;
|
||||
|
||||
temp_vgmstream = init_vgmstream_ps3_msf(temp_streamFile);
|
||||
@ -362,7 +361,7 @@ VGMSTREAM * init_vgmstream_ubi_jade_container(STREAMFILE *streamFile) {
|
||||
|
||||
subfile_size = read_32bitLE(subfile_offset+0x04,streamFile) + 0x04+0x04;
|
||||
|
||||
temp_streamFile = setup_jade_streamfile(streamFile, subfile_offset,subfile_size, NULL);
|
||||
temp_streamFile = setup_subfile_streamfile(streamFile, subfile_offset,subfile_size, NULL);
|
||||
if (!temp_streamFile) goto fail;
|
||||
|
||||
if (check_extensions(streamFile,"xma")) {
|
||||
@ -379,28 +378,3 @@ fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static STREAMFILE* setup_jade_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size, const char* fake_ext) {
|
||||
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||
|
||||
/* setup subfile */
|
||||
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 (fake_ext) {
|
||||
new_streamFile = open_fakename_streamfile(temp_streamFile, NULL,fake_ext);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
}
|
||||
|
||||
return temp_streamFile;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -2,10 +2,11 @@
|
||||
#include "../layout/layout.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* .vs/VS - from Final Fantasy X voices (PS2) */
|
||||
|
||||
/* VS - VagStream from Square games [Final Fantasy X (PS2) voices, Unlimited Saga (PS2) voices] */
|
||||
VGMSTREAM * init_vgmstream_vs_ffx(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
int channel_count, loop_flag;
|
||||
int channel_count, loop_flag, pitch;
|
||||
off_t start_offset;
|
||||
|
||||
|
||||
@ -13,9 +14,16 @@ VGMSTREAM * init_vgmstream_vs_ffx(STREAMFILE *streamFile) {
|
||||
/* .vs: header id (probably ok like The Bouncer's .vs, very similar) */
|
||||
if (!check_extensions(streamFile, "vs"))
|
||||
goto fail;
|
||||
if (read_32bitBE(0x00,streamFile) != 0x56530000) /* "VS\0\0" */
|
||||
if (read_32bitBE(0x00,streamFile) != 0x56530000) /* "VS\0\0" */
|
||||
goto fail;
|
||||
|
||||
/* 0x04: null (flags? used in SVS) */
|
||||
/* 0x08: block number */
|
||||
/* 0x0c: blocks left in the subfile */
|
||||
pitch = read_32bitLE(0x10,streamFile); /* usually 0x1000 = 48000 */
|
||||
/* 0x14: volume, usually 0x64 = 100 but be bigger/smaller (up to 128?) */
|
||||
/* 0x18: null */
|
||||
/* 0x1c: null */
|
||||
|
||||
loop_flag = 0;
|
||||
channel_count = 1;
|
||||
@ -27,7 +35,7 @@ VGMSTREAM * init_vgmstream_vs_ffx(STREAMFILE *streamFile) {
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_VS_FFX;
|
||||
vgmstream->sample_rate = 48000;
|
||||
vgmstream->sample_rate = (48000 * pitch) / 4096; /* verified, needed for rare files */
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_blocked_vs_ffx;
|
||||
|
||||
|
@ -369,9 +369,10 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
||||
|
||||
start_offset += audio_offset;
|
||||
|
||||
/* Vorbis is VBR so this is very approximate, meh */
|
||||
/* Vorbis is VBR so this is very approximate percent, meh */
|
||||
if (ww.truncated)
|
||||
vgmstream->num_samples = vgmstream->num_samples * (ww.file_size - start_offset) / ww.data_size;
|
||||
vgmstream->num_samples = (int32_t)(vgmstream->num_samples *
|
||||
(double)(ww.file_size - start_offset) / (double)ww.data_size);
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -72,7 +72,6 @@ typedef struct {
|
||||
} xwb_header;
|
||||
|
||||
static void get_name(char * buf, size_t maxsize, int target_subsong, xwb_header * xwb, STREAMFILE *streamFile);
|
||||
static STREAMFILE* setup_subfile_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size, const char* fake_ext);
|
||||
|
||||
|
||||
/* XWB - XACT Wave Bank (Microsoft SDK format for XBOX/XBOX360/Windows) */
|
||||
@ -600,31 +599,6 @@ fail:
|
||||
|
||||
/* ****************************************************************************** */
|
||||
|
||||
static STREAMFILE* setup_subfile_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size, const char* fake_ext) {
|
||||
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||
|
||||
/* setup subfile */
|
||||
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;
|
||||
|
||||
new_streamFile = open_fakename_streamfile(temp_streamFile, NULL,fake_ext);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
return temp_streamFile;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ****************************************************************************** */
|
||||
|
||||
/* try to get the stream name in the .xwb, though they are very rarely included */
|
||||
static int get_xwb_name(char * buf, size_t maxsize, int target_subsong, xwb_header * xwb, STREAMFILE *streamFile) {
|
||||
size_t read;
|
||||
|
@ -445,6 +445,8 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
|
||||
init_vgmstream_xwma,
|
||||
init_vgmstream_xopus,
|
||||
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) */
|
||||
init_vgmstream_txth, /* proper parsers should supersede TXTH, once added */
|
||||
|
@ -342,7 +342,7 @@ typedef enum {
|
||||
meta_PS2_BMDX, /* Beatmania thing */
|
||||
meta_PS2_IVB, /* Langrisser 3 IVB */
|
||||
meta_PS2_SND, /* some Might & Magics SSND header */
|
||||
meta_PS2_SVS, /* Square SVS */
|
||||
meta_SVS, /* Square SVS */
|
||||
meta_XSS, /* Dino Crisis 3 */
|
||||
meta_SL3, /* Test Drive Unlimited */
|
||||
meta_HGC1, /* Knights of the Temple 2 */
|
||||
@ -432,8 +432,7 @@ typedef enum {
|
||||
meta_RSD6WMA, /* RSD6WMA */
|
||||
|
||||
meta_PS2_ASS, /* ASS */
|
||||
meta_PS2_SEG, /* Eragon */
|
||||
meta_XBOX_SEG, /* Eragon */
|
||||
meta_SEG, /* Eragon */
|
||||
meta_NDS_STRM_FFTA2, /* Final Fantasy Tactics A2 */
|
||||
meta_STR_ASR, /* Donkey Kong Jet Race */
|
||||
meta_ZWDSP, /* Zack and Wiki */
|
||||
|
Loading…
Reference in New Issue
Block a user