mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-25 23:30:23 +01:00
commit
7a458c0bc3
@ -77,7 +77,7 @@ int main(int argc, char ** argv) {
|
||||
int print_adxencd = 0;
|
||||
int print_oggenc = 0;
|
||||
int print_batchvar = 0;
|
||||
int write_lwav = 0;
|
||||
int write_lwav = 0, write_lwav_loop_start = 0, write_lwav_loop_end = 0;
|
||||
int only_stereo = -1;
|
||||
int stream_index = 0;
|
||||
double loop_count = 2.0;
|
||||
@ -220,6 +220,12 @@ int main(int argc, char ** argv) {
|
||||
vgmstream_force_loop(vgmstream, 0, 0,0);
|
||||
}
|
||||
|
||||
if (write_lwav) {
|
||||
write_lwav_loop_start = vgmstream->loop_start_sample;
|
||||
write_lwav_loop_end = vgmstream->loop_end_sample;
|
||||
vgmstream_force_loop(vgmstream, 0, 0,0);
|
||||
}
|
||||
|
||||
if (play_sdtout) {
|
||||
if (outfilename) {
|
||||
fprintf(stderr,"either -p or -o, make up your mind\n");
|
||||
@ -318,17 +324,11 @@ int main(int argc, char ** argv) {
|
||||
{
|
||||
uint8_t wav_buf[0x100];
|
||||
int channels = (only_stereo != -1) ? 2 : vgmstream->channels;
|
||||
int smpl_chunk = (write_lwav && vgmstream->loop_flag);
|
||||
size_t bytes_done;
|
||||
|
||||
bytes_done = make_wav_header(wav_buf,0x100,
|
||||
len_samples, vgmstream->sample_rate, channels,
|
||||
smpl_chunk, vgmstream->loop_start_sample, vgmstream->loop_end_sample);
|
||||
|
||||
/* once "smpl" with loops is written we don't want actual file looping */
|
||||
if (smpl_chunk) {
|
||||
vgmstream_force_loop(vgmstream, 0, 0,0);
|
||||
}
|
||||
write_lwav, write_lwav_loop_start, write_lwav_loop_end);
|
||||
|
||||
fwrite(wav_buf,sizeof(uint8_t),bytes_done,outfile);
|
||||
}
|
||||
@ -407,26 +407,22 @@ int main(int argc, char ** argv) {
|
||||
vgmstream_force_loop(vgmstream, 0, 0,0);
|
||||
}
|
||||
|
||||
if (write_lwav) {
|
||||
write_lwav_loop_start = vgmstream->loop_start_sample;
|
||||
write_lwav_loop_end = vgmstream->loop_end_sample;
|
||||
vgmstream_force_loop(vgmstream, 0, 0,0);
|
||||
}
|
||||
|
||||
/* slap on a .wav header */
|
||||
{
|
||||
uint8_t wav_buf[0x100];
|
||||
int channels = (only_stereo != -1) ? 2 : vgmstream->channels;
|
||||
int smpl_chunk = (write_lwav && vgmstream->loop_flag);
|
||||
size_t bytes_done;
|
||||
|
||||
bytes_done = make_wav_header(wav_buf,0x100,
|
||||
len_samples, vgmstream->sample_rate, channels,
|
||||
smpl_chunk, vgmstream->loop_start_sample, vgmstream->loop_end_sample);
|
||||
write_lwav, write_lwav_loop_start, write_lwav_loop_end);
|
||||
|
||||
/* once "smpl" with looping is written we don't want actual file looping */
|
||||
if (smpl_chunk) {
|
||||
vgmstream_force_loop(vgmstream, 0, 0,0);
|
||||
}
|
||||
|
||||
if (write_lwav && vgmstream->loop_flag) { // Adding space for smpl chunk at end
|
||||
int32_t bytecount = get_32bitLE((uint8_t*)buf + 4);
|
||||
put_32bitLE((uint8_t*)buf + 4, bytecount + 0x44);
|
||||
}
|
||||
fwrite(wav_buf,sizeof(uint8_t),bytes_done,outfile);
|
||||
}
|
||||
|
||||
@ -499,7 +495,7 @@ static size_t make_wav_header(uint8_t * buf, size_t buf_size, int32_t sample_cou
|
||||
|
||||
data_size = sample_count*channels*sizeof(sample);
|
||||
header_size = 0x2c;
|
||||
if (smpl_chunk)
|
||||
if (smpl_chunk && loop_end)
|
||||
header_size += 0x3c+ 0x08;
|
||||
|
||||
if (header_size > buf_size)
|
||||
@ -519,7 +515,7 @@ static size_t make_wav_header(uint8_t * buf, size_t buf_size, int32_t sample_cou
|
||||
put_16bitLE(buf+0x20, (int16_t)(channels*sizeof(sample))); /* block align */
|
||||
put_16bitLE(buf+0x22, sizeof(sample)*8); /* significant bits per sample */
|
||||
|
||||
if (smpl_chunk) {
|
||||
if (smpl_chunk && loop_end) {
|
||||
make_smpl_chunk(buf+0x24, loop_start, loop_end);
|
||||
memcpy(buf+0x24+0x3c+0x08, "data", 0x04); /* WAVE data chunk */
|
||||
put_32bitLE(buf+0x28+0x3c+0x08, (int32_t)data_size); /* size of WAVE data chunk */
|
||||
|
@ -58,7 +58,11 @@ int mpeg_custom_setup_init_default(STREAMFILE *streamFile, off_t start_offset, m
|
||||
break;
|
||||
|
||||
case MPEG_LYN:
|
||||
goto fail; /* not fully implemented */
|
||||
if (data->config.interleave <= 0)
|
||||
goto fail; /* needs external fixed size */
|
||||
data->default_buffer_size = data->config.interleave;
|
||||
//todo simplify/unify XVAG/P3D/SCD/LYN and just feed arbitrary chunks to the decoder
|
||||
break;
|
||||
|
||||
case MPEG_STANDARD:
|
||||
case MPEG_AHX:
|
||||
@ -137,9 +141,9 @@ int mpeg_custom_parse_frame_default(VGMSTREAMCHANNEL *stream, mpeg_codec_data *d
|
||||
|
||||
case MPEG_P3D: /* fixed interleave, not frame-aligned (ie. blocks may end/start in part of a frame) */
|
||||
case MPEG_SCD:
|
||||
case MPEG_LYN:
|
||||
current_interleave = data->config.interleave;
|
||||
|
||||
#if 1
|
||||
/* check if current interleave block is short */
|
||||
{
|
||||
off_t block_offset = stream->offset - stream->channel_start_offset;
|
||||
@ -148,7 +152,7 @@ int mpeg_custom_parse_frame_default(VGMSTREAMCHANNEL *stream, mpeg_codec_data *d
|
||||
if (data->config.data_size && block_offset + next_block >= data->config.data_size)
|
||||
current_interleave = (data->config.data_size % next_block) / data->streams_size; /* short_interleave*/
|
||||
}
|
||||
#endif
|
||||
|
||||
current_interleave_pre = current_interleave*num_stream;
|
||||
current_interleave_post = current_interleave*(data->streams_size-1) - current_interleave_pre;
|
||||
|
||||
@ -162,7 +166,7 @@ int mpeg_custom_parse_frame_default(VGMSTREAMCHANNEL *stream, mpeg_codec_data *d
|
||||
break;
|
||||
}
|
||||
if (!current_data_size || current_data_size > ms->buffer_size) {
|
||||
VGM_LOG("MPEG: incorrect data_size 0x%x\n", current_data_size);
|
||||
VGM_LOG("MPEG: incorrect data_size 0x%x vs buffer 0x%x\n", current_data_size, ms->buffer_size);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
@ -638,7 +638,7 @@ fail:
|
||||
}
|
||||
|
||||
|
||||
/* Skip EA-frames from other streams for multichannel (interleaved 1 EA-frame per stream).
|
||||
/* Skip EA-frames from other streams for .sns/sps multichannel (interleaved 1 EA-frame per stream).
|
||||
* Due to EALayer3 being in blocks and other complexities (we can't go past a block) all
|
||||
* streams's offsets should start in the first stream's EA-frame.
|
||||
*
|
||||
@ -649,6 +649,8 @@ fail:
|
||||
* - skip one EA-frame per following streams until offset is in first stream's EA-frame
|
||||
* (ie. 1st stream skips 2, 2nd stream skips 1, 3rd stream skips 0)
|
||||
* - repeat again for granule1
|
||||
*
|
||||
* EALayer3 v1 in SCHl uses external offsets and 1ch multichannel instead.
|
||||
*/
|
||||
static int ealayer3_skip_data(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream, int at_start) {
|
||||
int ok, i;
|
||||
@ -657,6 +659,9 @@ static int ealayer3_skip_data(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, i
|
||||
uint8_t ibuf[EALAYER3_EA_FRAME_BUFFER_SIZE];
|
||||
int skips = at_start ? num_stream : data->streams_size - 1 - num_stream;
|
||||
|
||||
/* v1 does multichannel with set offsets */
|
||||
if (data->type == MPEG_EAL31)
|
||||
return 1;
|
||||
|
||||
for (i = 0; i < skips; i++) {
|
||||
is.buf = ibuf;
|
||||
|
@ -131,6 +131,8 @@ mpeg_codec_data *init_mpeg_custom(STREAMFILE *streamFile, off_t start_offset, co
|
||||
memcpy(&data->config, config, sizeof(mpeg_custom_config));
|
||||
data->config.channels = channels;
|
||||
|
||||
data->default_buffer_size = MPEG_DATA_BUFFER_SIZE;
|
||||
|
||||
/* init per subtype */
|
||||
switch(data->type) {
|
||||
case MPEG_EAL31:
|
||||
@ -145,6 +147,7 @@ mpeg_codec_data *init_mpeg_custom(STREAMFILE *streamFile, off_t start_offset, co
|
||||
|
||||
if (channels <= 0 || channels > 16) goto fail; /* arbitrary max */
|
||||
if (channels < data->channels_per_frame) goto fail;
|
||||
if (data->default_buffer_size > 0x8000) goto fail;
|
||||
|
||||
|
||||
/* init streams */
|
||||
@ -161,7 +164,7 @@ mpeg_codec_data *init_mpeg_custom(STREAMFILE *streamFile, off_t start_offset, co
|
||||
if (!data->streams[i]->output_buffer) goto fail;
|
||||
|
||||
/* one per stream as sometimes mpg123 can't read the whole buffer in one pass */
|
||||
data->streams[i]->buffer_size = MPEG_DATA_BUFFER_SIZE;
|
||||
data->streams[i]->buffer_size = data->default_buffer_size;
|
||||
data->streams[i]->buffer = calloc(sizeof(uint8_t), data->streams[i]->buffer_size);
|
||||
if (!data->streams[i]->buffer) goto fail;
|
||||
}
|
||||
|
@ -198,7 +198,9 @@ static const char* extension_list[] = {
|
||||
//"mpc", //FFmpeg, not parsed (musepack) //common
|
||||
"mpdsp",
|
||||
"mpds",
|
||||
"ms",
|
||||
"msa",
|
||||
"msb",
|
||||
"msd",
|
||||
"msf",
|
||||
"mss",
|
||||
@ -241,7 +243,7 @@ static const char* extension_list[] = {
|
||||
"ps2stm", //fake extension for .stm (to be removed)
|
||||
"psh", // fake extension for VSV(?) Dawn of Mana needs to be checked again
|
||||
"psnd",
|
||||
"psw",
|
||||
"psw", //fake extension for .wam
|
||||
|
||||
"r",
|
||||
"rac", //txth/reserved [Manhunt (Xbox)]
|
||||
@ -292,6 +294,7 @@ static const char* extension_list[] = {
|
||||
"sgd",
|
||||
"sgx",
|
||||
"sl3",
|
||||
"slb", //txth/reserved [THE Nekomura no Hitobito (PS2)]
|
||||
"sli",
|
||||
"smp",
|
||||
"smpl", //fake extension (to be removed)
|
||||
@ -303,6 +306,7 @@ static const char* extension_list[] = {
|
||||
"snr",
|
||||
"sns",
|
||||
"snu",
|
||||
"son",
|
||||
"spd",
|
||||
"spm",
|
||||
"sps",
|
||||
@ -346,6 +350,7 @@ static const char* extension_list[] = {
|
||||
"vawx",
|
||||
"vb",
|
||||
"vbk",
|
||||
"vbx", //txth/reserved [THE Taxi 2 (PS2)]
|
||||
"vds",
|
||||
"vdm",
|
||||
"vgs",
|
||||
@ -682,7 +687,7 @@ static const meta_info meta_info_list[] = {
|
||||
{meta_AUS, "Capcom AUS Header"},
|
||||
{meta_RWS, "RenderWare RWS header"},
|
||||
{meta_EA_1SNH, "Electronic Arts 1SNh/EACS header"},
|
||||
{meta_SL3, "SL3 Header"},
|
||||
{meta_SL3, "Atari Melbourne House SL3 header"},
|
||||
{meta_FSB1, "FMOD Sample Bank (FSB1) Header"},
|
||||
{meta_FSB2, "FMOD Sample Bank (FSB2) Header"},
|
||||
{meta_FSB3, "FMOD Sample Bank (FSB3) Header"},
|
||||
@ -719,7 +724,6 @@ static const meta_info meta_info_list[] = {
|
||||
{meta_SCD_PCM, "Lunar: Eternal Blue .PCM header"},
|
||||
{meta_PS2_PCM, "Konami KCEJ East .PCM header"},
|
||||
{meta_PS2_RKV, "Legacy of Kain - Blood Omen 2 RKV PS2 header"},
|
||||
{meta_PS2_PSW, "Rayman Raving Rabbids Riff Container File"},
|
||||
{meta_PS2_VAS, "Pro Baseball Spirits 5 VAS Header"},
|
||||
{meta_PS2_TEC, "assumed TECMO badflagged stream by .tec extension"},
|
||||
{meta_XBOX_WVS, "Metal Arms WVS Header (XBOX)"},
|
||||
@ -764,7 +768,7 @@ static const meta_info meta_info_list[] = {
|
||||
{meta_FFXI_SPW, "SPW SeWave header"},
|
||||
{meta_PS2_ASS, "ASS Header"},
|
||||
{meta_IDSP, "IDSP Header"},
|
||||
{meta_WAA_WAC_WAD_WAM, "WAA/WAC/WAD/WAM RIFF Header"},
|
||||
{meta_UBI_JADE, "Ubisoft Jade RIFF header"},
|
||||
{meta_PS2_SEG, "SEG (PS2) Header"},
|
||||
{meta_XBOX_SEG, "SEG (XBOX) Header"},
|
||||
{meta_NDS_STRM_FFTA2, "Final Fantasy Tactics A2 RIFF Header"},
|
||||
@ -790,7 +794,6 @@ static const meta_info meta_info_list[] = {
|
||||
{meta_NGC_DSP_IADP, "IADP Header"},
|
||||
{meta_RSTM_shrunken, "Nintendo RSTM header, corrupted by Atlus"},
|
||||
{meta_RIFF_WAVE_MWV, "RIFF WAVE header with .mwv flavoring"},
|
||||
{meta_RIFF_WAVE_SNS, "RIFF WAVE header with .sns flavoring"},
|
||||
{meta_FFCC_STR, "Final Fantasy: Crystal Chronicles STR header"},
|
||||
{meta_SAT_BAKA, "BAKA header from Crypt Killer"},
|
||||
{meta_NDS_SWAV, "SWAV Header"},
|
||||
@ -984,6 +987,9 @@ static const meta_info meta_info_list[] = {
|
||||
{meta_MP4, "MP4/AAC header"},
|
||||
{meta_PCM_SRE, "Capcom .PCM+SRE header"},
|
||||
{meta_DSP_MCADPCM, "Bethesda .mcadpcm header"},
|
||||
{meta_UBI_LYN, "Ubisoft LyN RIFF header"},
|
||||
{meta_MSB_MSH, "Sony MSB+MSH header"},
|
||||
{meta_OGG_RPGMV, "Ogg Vorbis (RPGMV header)"},
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
{meta_FFmpeg, "FFmpeg supported file format"},
|
||||
|
@ -126,14 +126,22 @@ void block_update_ea_schl(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
break;
|
||||
|
||||
#ifdef VGM_USE_MPEG
|
||||
/* id, size, samples, offset?, unknown (null for MP2, some constant for all blocks for EALayer3) */
|
||||
/* id, size, samples, offsets, unknown (null for MP2, some size/config for EALayer3; only if not >2ch) */
|
||||
case coding_MPEG_custom:
|
||||
case coding_MPEG_layer1:
|
||||
case coding_MPEG_layer2:
|
||||
case coding_MPEG_layer3:
|
||||
case coding_MPEG_ealayer3:
|
||||
for (i = 0; i < vgmstream->channels; i++) {
|
||||
off_t channel_start = read_32bit(block_offset + 0x0C,streamFile);
|
||||
off_t channel_start;
|
||||
|
||||
/* EALayer3 6ch uses 1ch*6 with offsets, no flag in header [Medal of Honor 2010 (PC) movies] */
|
||||
if (vgmstream->channels > 2) {
|
||||
channel_start = read_32bit(block_offset + 0x0C + 0x04*i,streamFile);
|
||||
} else {
|
||||
channel_start = read_32bit(block_offset + 0x0C,streamFile);
|
||||
}
|
||||
|
||||
vgmstream->ch[i].offset = block_offset + 0x0C + (0x04*vgmstream->channels) + channel_start;
|
||||
}
|
||||
|
||||
|
@ -231,6 +231,10 @@
|
||||
<File
|
||||
RelativePath=".\meta\sqex_scd_streamfile.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\ubi_lyn_ogg_streamfile.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
@ -930,6 +934,14 @@
|
||||
RelativePath=".\meta\ps2_msa.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\mp4.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\msb_msh.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\mss.c"
|
||||
>
|
||||
@ -958,10 +970,6 @@
|
||||
RelativePath=".\meta\ps2_psh.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\ps2_psw.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\ps2_rnd.c"
|
||||
>
|
||||
@ -1278,6 +1286,10 @@
|
||||
RelativePath=".\meta\ubi_ckd.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\ubi_lyn.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\ubi_raki.c"
|
||||
>
|
||||
@ -1307,7 +1319,7 @@
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\waa_wac_wad_wam.c"
|
||||
RelativePath=".\meta\ubi_jade.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
|
@ -100,6 +100,7 @@
|
||||
<ClInclude Include="meta\bar_streamfile.h" />
|
||||
<ClInclude Include="meta\ea_eaac_eatrax_streamfile.h" />
|
||||
<ClInclude Include="meta\sqex_scd_streamfile.h" />
|
||||
<ClInclude Include="meta\ubi_lyn_ogg_streamfile.h" />
|
||||
<ClInclude Include="meta\meta.h" />
|
||||
<ClInclude Include="meta\hca_keys.h" />
|
||||
<ClInclude Include="meta\fsb_keys.h" />
|
||||
@ -143,6 +144,7 @@
|
||||
<ClCompile Include="meta\mn_str.c" />
|
||||
<ClCompile Include="meta\mogg.c" />
|
||||
<ClCompile Include="meta\mp4.c" />
|
||||
<ClCompile Include="meta\msb_msh.c" />
|
||||
<ClCompile Include="meta\ngca.c" />
|
||||
<ClCompile Include="meta\nsw_opus.c" />
|
||||
<ClCompile Include="meta\nub_vag.c" />
|
||||
@ -334,7 +336,6 @@
|
||||
<ClCompile Include="meta\ps2_pcm.c" />
|
||||
<ClCompile Include="meta\ps2_pnb.c" />
|
||||
<ClCompile Include="meta\ps2_psh.c" />
|
||||
<ClCompile Include="meta\ps2_psw.c" />
|
||||
<ClCompile Include="meta\ps2_rnd.c" />
|
||||
<ClCompile Include="meta\ps2_rstm.c" />
|
||||
<ClCompile Include="meta\ps2_rxws.c" />
|
||||
@ -400,13 +401,14 @@
|
||||
<ClCompile Include="meta\thp.c" />
|
||||
<ClCompile Include="meta\vgs.c" />
|
||||
<ClCompile Include="meta\ubi_ckd.c" />
|
||||
<ClCompile Include="meta\ubi_lyn.c" />
|
||||
<ClCompile Include="meta\ubi_raki.c" />
|
||||
<ClCompile Include="meta\ubi_sb.c" />
|
||||
<ClCompile Include="meta\vs.c" />
|
||||
<ClCompile Include="meta\vsf.c" />
|
||||
<ClCompile Include="meta\vsf_tta.c" />
|
||||
<ClCompile Include="meta\vxn.c" />
|
||||
<ClCompile Include="meta\waa_wac_wad_wam.c" />
|
||||
<ClCompile Include="meta\ubi_jade.c" />
|
||||
<ClCompile Include="meta\waf.c" />
|
||||
<ClCompile Include="meta\wave_segmented.c" />
|
||||
<ClCompile Include="meta\wave.c" />
|
||||
|
@ -80,6 +80,9 @@
|
||||
<ClInclude Include="meta\sqex_scd_streamfile.h">
|
||||
<Filter>meta\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="meta\ubi_lyn_ogg_streamfile.h">
|
||||
<Filter>meta\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="meta\meta.h">
|
||||
<Filter>meta\Header Files</Filter>
|
||||
</ClInclude>
|
||||
@ -583,9 +586,6 @@
|
||||
<ClCompile Include="meta\ps2_psh.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\ps2_psw.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\ps2_rnd.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
@ -781,6 +781,9 @@
|
||||
<ClCompile Include="meta\ubi_ckd.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\ubi_lyn.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\ubi_raki.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
@ -799,7 +802,7 @@
|
||||
<ClCompile Include="meta\vxn.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\waa_wac_wad_wam.c">
|
||||
<ClCompile Include="meta\ubi_jade.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\waf.c">
|
||||
@ -1231,6 +1234,9 @@
|
||||
<ClCompile Include="meta\mp4.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\msb_msh.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="coding\mp4_aac_decoder.c">
|
||||
<Filter>coding\Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
@ -221,8 +221,6 @@ VGMSTREAM * init_vgmstream_ps2_pcm(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ps2_rkv(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ps2_psw(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ps2_vas(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ps2_tec(STREAMFILE * streamFile);
|
||||
@ -319,7 +317,8 @@ VGMSTREAM * init_vgmstream_spw(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ps2_ass(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_waa_wac_wad_wam(STREAMFILE * streamFile);
|
||||
VGMSTREAM * init_vgmstream_ubi_jade(STREAMFILE * streamFile);
|
||||
VGMSTREAM * init_vgmstream_ubi_jade_container(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_seg(STREAMFILE * streamFile);
|
||||
|
||||
@ -730,4 +729,9 @@ VGMSTREAM * init_vgmstream_pcm_sre(STREAMFILE *streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_dsp_mcadpcm(STREAMFILE *streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ubi_lyn(STREAMFILE * streamFile);
|
||||
VGMSTREAM * init_vgmstream_ubi_lyn_container(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_msb_msh(STREAMFILE * streamFile);
|
||||
|
||||
#endif /*_META_H*/
|
||||
|
86
src/meta/msb_msh.c
Normal file
86
src/meta/msb_msh.c
Normal file
@ -0,0 +1,86 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* MSB+MSH - Sony sfx container companion of MIH+MIB [namCollection - Ace Combat 2 (PS2) sfx, EyeToy Play (PS2)] */
|
||||
VGMSTREAM * init_vgmstream_msb_msh(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
STREAMFILE * streamHeader = NULL;
|
||||
off_t start_offset, header_offset = 0;
|
||||
size_t stream_size;
|
||||
int loop_flag = 0, channel_count, sample_rate;
|
||||
int total_subsongs, target_subsong = streamFile->stream_index;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "msb"))
|
||||
goto fail;
|
||||
|
||||
streamHeader = open_streamfile_by_ext(streamFile, "msh");
|
||||
if (!streamHeader) goto fail;
|
||||
|
||||
if (read_32bitLE(0x00,streamHeader) != get_streamfile_size(streamHeader))
|
||||
goto fail;
|
||||
/* 0x04: unknown */
|
||||
|
||||
/* parse entries */
|
||||
{
|
||||
int i;
|
||||
int entries = read_32bitLE(0x08,streamHeader);
|
||||
|
||||
total_subsongs = 0;
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
|
||||
for (i = 0; i < entries; i++) {
|
||||
if (read_32bitLE(0x0c + 0x10*i, streamHeader) == 0) /* size 0 = empty entry */
|
||||
continue;
|
||||
|
||||
total_subsongs++;
|
||||
if (total_subsongs == target_subsong && !header_offset) {
|
||||
header_offset = 0x0c + 0x10*i;
|
||||
}
|
||||
}
|
||||
|
||||
if (!header_offset) goto fail;
|
||||
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||
}
|
||||
|
||||
|
||||
|
||||
loop_flag = 0;
|
||||
channel_count = 1;
|
||||
|
||||
stream_size = read_32bitLE(header_offset+0x00, streamHeader);
|
||||
if (read_32bitLE(header_offset+0x04, streamHeader) != 0) /* stereo flag? */
|
||||
goto fail;
|
||||
start_offset = read_32bitLE(header_offset+0x08, streamHeader);
|
||||
sample_rate = read_32bitLE(header_offset+0x0c, streamHeader); /* Ace Combat 2 seems to set wrong values but probably their bug */
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->num_samples = ps_bytes_to_samples(stream_size,channel_count);
|
||||
|
||||
vgmstream->num_streams = total_subsongs;
|
||||
vgmstream->stream_size = stream_size;
|
||||
vgmstream->meta_type = meta_MSB_MSH;
|
||||
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x10;
|
||||
|
||||
|
||||
close_streamfile(streamHeader);
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
|
||||
fail:
|
||||
close_streamfile(streamHeader);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
@ -176,6 +176,29 @@ static void l2sd_ogg_decryption_callback(void *ptr, size_t size, size_t nmemb, v
|
||||
}
|
||||
}
|
||||
|
||||
static void rpgmvo_ogg_decryption_callback(void *ptr, size_t size, size_t nmemb, void *datasource) {
|
||||
static const uint8_t header[16] = { /* OggS, packet type, granule, stream id(empty) */
|
||||
0x4F,0x67,0x67,0x53,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
|
||||
};
|
||||
size_t bytes_read = size*nmemb;
|
||||
ogg_vorbis_streamfile * const ov_streamfile = datasource;
|
||||
int i;
|
||||
|
||||
/* first 0x10 are xor'd with a key, but the header can be easily reconstructed
|
||||
* (key is also in (game)/www/data/System.json "encryptionKey") */
|
||||
for (i = 0; i < bytes_read; i++) {
|
||||
if (ov_streamfile->offset+i < 0x10) {
|
||||
((uint8_t*)ptr)[i] = header[(ov_streamfile->offset + i) % 16];
|
||||
|
||||
/* last two bytes are the stream id, get from next OggS */
|
||||
if (ov_streamfile->offset+i == 0x0e)
|
||||
((uint8_t*)ptr)[i] = read_8bit(0x58, ov_streamfile->streamfile);
|
||||
if (ov_streamfile->offset+i == 0x0f)
|
||||
((uint8_t*)ptr)[i] = read_8bit(0x59, ov_streamfile->streamfile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Ogg Vorbis, by way of libvorbisfile; may contain loop comments */
|
||||
VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) {
|
||||
@ -189,6 +212,7 @@ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) {
|
||||
int is_sngw = 0;
|
||||
int is_isd = 0;
|
||||
int is_l2sd = 0;
|
||||
int is_rpgmvo = 0;
|
||||
|
||||
|
||||
/* check extension */
|
||||
@ -206,6 +230,8 @@ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) {
|
||||
is_sngw = 1;
|
||||
} else if (check_extensions(streamFile,"isd")) { /* .isd: Azure Striker Gunvolt (PC) */
|
||||
is_isd = 1;
|
||||
} else if (check_extensions(streamFile,"rpgmvo")) { /* .rpgmvo: RPG Maker MV games (PC) */
|
||||
is_rpgmvo = 1;
|
||||
} else {
|
||||
goto fail;
|
||||
}
|
||||
@ -267,6 +293,18 @@ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) {
|
||||
// 0x0c(2): PCM block size, 0x0e(2): PCM bps, 0x10: null, 0x18: samples (in PCM bytes)
|
||||
}
|
||||
|
||||
/* check RPGMKVO (RPG Maker MV), header + minor encryption */
|
||||
if (is_rpgmvo) {
|
||||
if (read_32bitBE(0x00,streamFile) != 0x5250474D && /* "RPGM" */
|
||||
read_32bitBE(0x00,streamFile) != 0x56000000) { /* "V\0\0\0" */
|
||||
goto fail;
|
||||
}
|
||||
ovmi.decryption_callback = rpgmvo_ogg_decryption_callback;
|
||||
|
||||
start_offset = 0x10;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (is_um3) {
|
||||
ovmi.meta_type = meta_OGG_UM3;
|
||||
@ -280,6 +318,8 @@ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) {
|
||||
ovmi.meta_type = meta_OGG_ISD;
|
||||
} else if (is_l2sd) {
|
||||
ovmi.meta_type = meta_OGG_L2SD;
|
||||
} else if (is_rpgmvo) {
|
||||
ovmi.meta_type = meta_OGG_RPGMV;
|
||||
} else {
|
||||
ovmi.meta_type = meta_OGG_VORBIS;
|
||||
}
|
||||
|
@ -1,88 +0,0 @@
|
||||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* PSW (from Rayman Raving Rabbids)
|
||||
...coefs are missing for the dsp type... */
|
||||
VGMSTREAM * init_vgmstream_ps2_psw(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
off_t start_offset;
|
||||
int loop_flag = 0;
|
||||
int channel_count;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("psw",filename_extension(filename))) goto fail;
|
||||
|
||||
/* check header */
|
||||
if (read_32bitBE(0x00,streamFile) != 0x52494646 && /* "RIFF" */
|
||||
read_32bitBE(0x08,streamFile) != 0x57415645 && /* "WAVE" */
|
||||
read_32bitBE(0x26,streamFile) != 0x64617461) /* "data" */
|
||||
goto fail;
|
||||
|
||||
loop_flag = 0;
|
||||
channel_count = read_16bitLE(0x16,streamFile);
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
switch ((uint16_t)read_16bitBE(0x14,streamFile)) {
|
||||
case 0xFFFF:
|
||||
start_offset = 0x2E;
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = read_16bitLE(0x1C,streamFile);
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->num_samples = read_32bitLE(0x2A,streamFile)*28/16/channel_count;
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = loop_flag;
|
||||
vgmstream->loop_end_sample = read_32bitLE(0x2A,streamFile)*28/16/channel_count;
|
||||
}
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x6400;
|
||||
vgmstream->meta_type = meta_PS2_PSW;
|
||||
|
||||
break;
|
||||
case 0xFEFF:
|
||||
start_offset = 0x2E;
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = read_16bitLE(0x1C,streamFile);
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->num_samples = read_32bitLE(0x2A,streamFile)*28/16/channel_count;
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = loop_flag;
|
||||
vgmstream->loop_end_sample = read_32bitLE(0x2A,streamFile)*28/16/channel_count;
|
||||
}
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x12C00;
|
||||
vgmstream->meta_type = meta_PS2_PSW;
|
||||
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
@ -1,65 +1,45 @@
|
||||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* SL3 (from Test Drive Unlimited, Transformers) */
|
||||
/* SL3 - Atari Melbourne House games [ Test Drive Unlimited (PS2), Transformers (PS2)] */
|
||||
VGMSTREAM * init_vgmstream_sl3(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
off_t start_offset;
|
||||
int loop_flag = 0, channel_count;
|
||||
|
||||
int loop_flag = 0;
|
||||
int channel_count;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("sl3",filename_extension(filename))) goto fail;
|
||||
|
||||
/* check header */
|
||||
/* checks */
|
||||
/* .ms: actual extension, sl3: header id */
|
||||
if (!check_extensions(streamFile, "ms,sl3"))
|
||||
goto fail;
|
||||
if (read_32bitBE(0x00,streamFile) != 0x534C3300) /* "SL3\0" */
|
||||
goto fail;
|
||||
|
||||
loop_flag = 0;
|
||||
channel_count = read_32bitLE(0x14,streamFile);
|
||||
|
||||
start_offset = 0x8000; /* also at 0x24? */
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
start_offset = 0x8000;
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = read_32bitLE(0x18,streamFile);
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->num_samples = (get_streamfile_size(streamFile)-0x8000)*28/16/channel_count;
|
||||
vgmstream->num_samples = ps_bytes_to_samples(get_streamfile_size(streamFile)-start_offset,channel_count);
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = read_32bitLE(0x1C,streamFile);
|
||||
}
|
||||
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = read_32bitLE(0x20,streamFile);
|
||||
vgmstream->meta_type = meta_SL3;
|
||||
|
||||
/* 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,6 +1,5 @@
|
||||
|
||||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* TK5 (Tekken 5 Streams) */
|
||||
VGMSTREAM * init_vgmstream_ps2_tk5(STREAMFILE *streamFile) {
|
||||
@ -65,65 +64,46 @@ fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* TK1 (Tekken 5 Streams from Tekken (NamCollection)) */
|
||||
/* OVB - Tekken 5 Streams from Tekken (NamCollection) */
|
||||
VGMSTREAM * init_vgmstream_ps2_tk1(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
off_t start_offset;
|
||||
int loop_flag = 0;
|
||||
int channel_count;
|
||||
int loop_flag = 0, channel_count;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("tk1",filename_extension(filename))) goto fail;
|
||||
/* checks */
|
||||
/* .ovb: actual extension, tk1: fake extension */
|
||||
if (!check_extensions(streamFile, "ovb,tk1"))
|
||||
goto fail;
|
||||
|
||||
/* check header */
|
||||
if (read_32bitBE(0x00,streamFile) != 0x544B3553)
|
||||
goto fail;
|
||||
|
||||
loop_flag = (read_32bitLE(0x0C,streamFile)!=0);
|
||||
channel_count = 2;
|
||||
|
||||
start_offset = 0x800;
|
||||
/* NamCollection uses 44100 while Tekken 5 48000, no apparent way to tell them apart */
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
start_offset = 0x800;
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = 44100;
|
||||
vgmstream->num_samples = ps_bytes_to_samples(read_32bitLE(0x08,streamFile)*channel_count, channel_count);
|
||||
if (vgmstream->loop_flag) {
|
||||
vgmstream->loop_start_sample = read_32bitLE(0x08,streamFile)/16*28;
|
||||
vgmstream->loop_end_sample = vgmstream->loop_start_sample + ps_bytes_to_samples(read_32bitLE(0x0c,streamFile)*channel_count, channel_count);
|
||||
}
|
||||
|
||||
vgmstream->coding_type = coding_PSX_badflags;
|
||||
vgmstream->num_samples = read_32bitLE(0x08,streamFile)/16*28;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x10;
|
||||
vgmstream->meta_type = meta_PS2_TK1;
|
||||
|
||||
if (vgmstream->loop_flag)
|
||||
{
|
||||
vgmstream->loop_start_sample = read_32bitLE(0x08,streamFile)/16*28;
|
||||
vgmstream->loop_end_sample = vgmstream->loop_start_sample + (read_32bitLE(0x0C,streamFile)/16*28);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ typedef struct {
|
||||
int interleave;
|
||||
} riff_fmt_chunk;
|
||||
|
||||
static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk, riff_fmt_chunk * fmt, int sns, int mwv) {
|
||||
static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk, riff_fmt_chunk * fmt, int mwv) {
|
||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = big_endian ? read_32bitBE : read_32bitLE;
|
||||
int16_t (*read_16bit)(off_t,STREAMFILE*) = big_endian ? read_16bitBE : read_16bitLE;
|
||||
|
||||
@ -143,7 +143,7 @@ static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk
|
||||
fmt->coding_type = coding_AICA;
|
||||
break;
|
||||
|
||||
case 0x69: /* XBOX IMA ADPCM [Dynasty Warriors 5 (Xbox), Rayman Raving Rabbids 2 (PC) --maybe waa/wac/wam/wad?] */
|
||||
case 0x69: /* XBOX IMA ADPCM [Dynasty Warriors 5 (Xbox)] */
|
||||
if (fmt->bps != 4) goto fail;
|
||||
fmt->coding_type = coding_XBOX_IMA;
|
||||
break;
|
||||
@ -167,12 +167,6 @@ static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk
|
||||
fmt->interleave = 0x12;
|
||||
break;
|
||||
|
||||
case 0x5050: /* Ubisoft LyN engine's DSP (unofficial) */
|
||||
if (!sns) goto fail;
|
||||
fmt->coding_type = coding_NGC_DSP;
|
||||
fmt->interleave = 0x08;
|
||||
break;
|
||||
|
||||
#ifdef VGM_USE_VORBIS
|
||||
case 0x6771: /* Ogg Vorbis (mode 3+) */
|
||||
fmt->coding_type = coding_OGG_VORBIS;
|
||||
@ -221,7 +215,7 @@ static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk
|
||||
#endif
|
||||
}
|
||||
|
||||
break;
|
||||
goto fail;
|
||||
|
||||
default:
|
||||
goto fail;
|
||||
@ -253,7 +247,6 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
||||
int mwv = 0; /* Level-5 .mwv (Dragon Quest VIII, Rogue Galaxy) */
|
||||
off_t mwv_pflt_offset = -1;
|
||||
off_t mwv_ctrl_offset = -1;
|
||||
int sns = 0; /* Ubisoft .sns LyN engine (Red Steel 2, Just Dance 3) */
|
||||
int at3 = 0; /* Sony ATRAC3 / ATRAC3plus */
|
||||
int at9 = 0; /* Sony ATRAC9 */
|
||||
|
||||
@ -269,9 +262,6 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
||||
else if ( check_extensions(streamFile, "mwv") ) {
|
||||
mwv = 1;
|
||||
}
|
||||
else if ( check_extensions(streamFile, "sns") ) {
|
||||
sns = 1;
|
||||
}
|
||||
/* .rws: Climax games (Silent Hill Origins PSP, Oblivion PSP), .aud: EA Replay */
|
||||
else if ( check_extensions(streamFile, "at3,rws,aud") ) {
|
||||
at3 = 1;
|
||||
@ -329,7 +319,6 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
||||
streamFile,
|
||||
current_chunk,
|
||||
&fmt,
|
||||
sns,
|
||||
mwv))
|
||||
goto fail;
|
||||
|
||||
@ -395,8 +384,8 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
||||
case 0x66616374: /* "fact" */
|
||||
if (chunk_size == 0x04) { /* standard, usually found with ADPCM */
|
||||
fact_sample_count = read_32bitLE(current_chunk+0x08, streamFile);
|
||||
} else if (sns && chunk_size == 0x10) {
|
||||
fact_sample_count = read_32bitLE(current_chunk+0x08, streamFile);
|
||||
} else if (chunk_size == 0x10 && read_32bitBE(current_chunk+0x08+0x04, streamFile) == 0x4C794E20) { /* "LyN " */
|
||||
goto fail; /* parsed elsewhere */
|
||||
} else if ((at3 || at9) && chunk_size == 0x08) {
|
||||
fact_sample_count = read_32bitLE(current_chunk+0x08, streamFile);
|
||||
fact_sample_skip = read_32bitLE(current_chunk+0x0c, streamFile);
|
||||
@ -441,6 +430,14 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
||||
&& (fmt.coding_type==coding_MSADPCM /*|| fmt.coding_type==coding_MS_IMA*/ || fmt.coding_type==coding_XBOX_IMA))
|
||||
goto fail;
|
||||
|
||||
/* ignore Beyond Good & Evil HD PS3 evil reuse of PCM codec */
|
||||
if (fmt.coding_type == coding_PCM16LE &&
|
||||
read_32bitBE(start_offset+0x00, streamFile) == 0x4D534643 && /* "MSF\43" */
|
||||
read_32bitBE(start_offset+0x34, streamFile) == 0xFFFFFFFF && /* always */
|
||||
read_32bitBE(start_offset+0x38, streamFile) == 0xFFFFFFFF &&
|
||||
read_32bitBE(start_offset+0x3c, streamFile) == 0xFFFFFFFF)
|
||||
goto fail;
|
||||
|
||||
|
||||
#ifdef VGM_USE_VORBIS
|
||||
/* special case using init_vgmstream_ogg_vorbis */
|
||||
@ -515,29 +512,6 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
||||
vgmstream->num_samples = fact_sample_count; /* some (converted?) Xbox games have bigger fact_samples */
|
||||
break;
|
||||
|
||||
case coding_NGC_DSP:
|
||||
if (!sns) goto fail;
|
||||
if (fact_sample_count <= 0) goto fail;
|
||||
vgmstream->num_samples = fact_sample_count;
|
||||
//vgmstream->num_samples = dsp_bytes_to_samples(data_size, fmt.channel_count);
|
||||
|
||||
/* coefs */
|
||||
{
|
||||
int i, ch;
|
||||
static const int16_t coef[16] = { /* common codebook? */
|
||||
0x04ab,0xfced,0x0789,0xfedf,0x09a2,0xfae5,0x0c90,0xfac1,
|
||||
0x084d,0xfaa4,0x0982,0xfdf7,0x0af6,0xfafa,0x0be6,0xfbf5
|
||||
};
|
||||
|
||||
for (ch = 0; ch < fmt.channel_count; ch++) {
|
||||
for (i = 0; i < 16; i++) {
|
||||
vgmstream->ch[ch].adpcm_coef[i] = coef[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
case coding_FFmpeg: {
|
||||
ffmpeg_codec_data *ffmpeg_data = init_ffmpeg_offset(streamFile, 0x00, streamFile->get_size(streamFile));
|
||||
@ -649,9 +623,6 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
||||
if (mwv) {
|
||||
vgmstream->meta_type = meta_RIFF_WAVE_MWV;
|
||||
}
|
||||
if (sns) {
|
||||
vgmstream->meta_type = meta_RIFF_WAVE_SNS;
|
||||
}
|
||||
|
||||
|
||||
if ( !vgmstream_open_stream(vgmstream,streamFile,start_offset) )
|
||||
@ -714,7 +685,6 @@ VGMSTREAM * init_vgmstream_rifx(STREAMFILE *streamFile) {
|
||||
streamFile,
|
||||
current_chunk,
|
||||
&fmt,
|
||||
0, /* sns == false */
|
||||
0)) /* mwv == false */
|
||||
goto fail;
|
||||
|
||||
|
389
src/meta/ubi_jade.c
Normal file
389
src/meta/ubi_jade.c
Normal file
@ -0,0 +1,389 @@
|
||||
#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)] */
|
||||
VGMSTREAM * init_vgmstream_ubi_jade(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset, first_offset = 0xc;
|
||||
off_t fmt_offset, data_offset;
|
||||
size_t fmt_size, data_size;
|
||||
int loop_flag, channel_count, sample_rate, codec, block_size;
|
||||
int loop_start = 0, loop_end = 0;
|
||||
int is_jade_v2 = 0;
|
||||
|
||||
|
||||
/* checks */
|
||||
/* .waa: ambiances, .wam: music, .wac: sfx, .wad: dialogs (usually)
|
||||
* .wav: Beyond Good & Evil HD (PS3), .psw: fake/badly extracted names [ex. Rayman Raving Rabbids (PS2)] */
|
||||
if (!check_extensions(streamFile,"waa,wac,wad,wam,wav,lwav,psw"))
|
||||
goto fail;
|
||||
|
||||
/* a slightly twisted RIFF with custom codecs */
|
||||
if (read_32bitBE(0x00,streamFile) != 0x52494646 || /* "RIFF" */
|
||||
read_32bitBE(0x08,streamFile) != 0x57415645) /* "WAVE" */
|
||||
goto fail;
|
||||
|
||||
if (check_extensions(streamFile,"psw")) { /* .psw are incorrectly extracted missing 0x04 at the end */
|
||||
if (read_32bitLE(0x04,streamFile)+0x04 != get_streamfile_size(streamFile))
|
||||
goto fail;
|
||||
}
|
||||
else {
|
||||
if (read_32bitLE(0x04,streamFile)+0x04+0x04 != get_streamfile_size(streamFile))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!find_chunk(streamFile, 0x666d7420,first_offset,0, &fmt_offset,&fmt_size, 0, 0)) /* "fmt " */
|
||||
goto fail;
|
||||
if (!find_chunk(streamFile, 0x64617461,first_offset,0, &data_offset,&data_size, 0, 0)) /* "data" */
|
||||
goto fail;
|
||||
|
||||
|
||||
/* parse format */
|
||||
{
|
||||
if (fmt_size < 0x10)
|
||||
goto fail;
|
||||
codec = (uint16_t)read_16bitLE(fmt_offset+0x00,streamFile);
|
||||
channel_count = read_16bitLE(fmt_offset+0x02,streamFile);
|
||||
sample_rate = read_32bitLE(fmt_offset+0x04,streamFile);
|
||||
block_size = (uint16_t)read_16bitLE(fmt_offset+0x0c,streamFile);
|
||||
/* 0x08: average bytes, 0x0e: bps, etc */
|
||||
|
||||
/* autodetect Jade "v2", uses a different interleave [Rayman Raving Rabbids (PS2/Wii)] */
|
||||
switch(codec) {
|
||||
case 0xFFFF: { /* PS2 */
|
||||
int i;
|
||||
|
||||
/* half interleave check as there is no flag (ends with the PS-ADPCM stop frame) */
|
||||
for (i = 0; i < channel_count; i++) {
|
||||
off_t end_frame = data_offset + (data_size / channel_count) * (i+1) - 0x10;
|
||||
if (read_32bitBE(end_frame+0x00,streamFile) != 0x07007777 ||
|
||||
read_32bitBE(end_frame+0x04,streamFile) != 0x77777777 ||
|
||||
read_32bitBE(end_frame+0x08,streamFile) != 0x77777777 ||
|
||||
read_32bitBE(end_frame+0x0c,streamFile) != 0x77777777) {
|
||||
is_jade_v2 = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xFFFE: /* GC/Wii */
|
||||
is_jade_v2 = (read_16bitLE(fmt_offset+0x10,streamFile) == 0); /* extra data size (0x2e*channels) */
|
||||
break;
|
||||
}
|
||||
|
||||
/* hopefully catches PC Rabbids */
|
||||
if (find_chunk(streamFile, 0x63756520,first_offset,0, NULL,NULL, 0, 0)) { /* "cue " */
|
||||
is_jade_v2 = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* get loop points */
|
||||
if (is_jade_v2) {
|
||||
loop_flag = get_loop_points(streamFile, &loop_start, &loop_end); /* loops in "LIST" */
|
||||
}
|
||||
else {
|
||||
/* BG&E files don't contain looping information, so the looping is done by extension.
|
||||
* wam and waa contain ambient sounds and music, so often they contain looped music.
|
||||
* Later, if the file is too short looping will be disabled. */
|
||||
loop_flag = check_extensions(streamFile,"waa,wam");
|
||||
}
|
||||
|
||||
start_offset = data_offset;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->meta_type = meta_UBI_JADE;
|
||||
if (is_jade_v2) {
|
||||
vgmstream->loop_start_sample = loop_start;
|
||||
vgmstream->loop_end_sample = loop_end;
|
||||
}
|
||||
|
||||
switch(codec) {
|
||||
|
||||
case 0x0069: /* Xbox */
|
||||
if (block_size != 0x24*channel_count)
|
||||
goto fail;
|
||||
vgmstream->coding_type = coding_XBOX_IMA;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
vgmstream->num_samples = xbox_ima_bytes_to_samples(data_size, channel_count);
|
||||
if (!is_jade_v2) {
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 0xFFFF: /* PS2 */
|
||||
if (block_size != 0x10)
|
||||
goto fail;
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
|
||||
if (is_jade_v2) {
|
||||
vgmstream->interleave_block_size = 0x6400;
|
||||
if (vgmstream->interleave_block_size)
|
||||
vgmstream->interleave_last_block_size = (data_size % (vgmstream->interleave_block_size*vgmstream->channels)) / vgmstream->channels;
|
||||
}
|
||||
else {
|
||||
vgmstream->interleave_block_size = data_size / channel_count;
|
||||
}
|
||||
|
||||
vgmstream->num_samples = ps_bytes_to_samples(data_size, channel_count);
|
||||
if (!is_jade_v2) {
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 0xFFFE: /* GC/Wii */
|
||||
if (block_size != 0x08)
|
||||
goto fail;
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
|
||||
vgmstream->num_samples = dsp_bytes_to_samples(data_size, channel_count);
|
||||
if (!is_jade_v2) {
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
}
|
||||
|
||||
/* coefs / interleave */
|
||||
if (is_jade_v2) {
|
||||
vgmstream->interleave_block_size = 0x6400;
|
||||
if (vgmstream->interleave_block_size)
|
||||
vgmstream->interleave_last_block_size = ((data_size % (vgmstream->interleave_block_size*vgmstream->channels))/2+7)/8*8;
|
||||
|
||||
{
|
||||
static const int16_t coef[16] = { /* default Ubisoft coefs, from ELF */
|
||||
0x04ab,0xfced,0x0789,0xfedf,0x09a2,0xfae5,0x0c90,0xfac1,
|
||||
0x084d,0xfaa4,0x0982,0xfdf7,0x0af6,0xfafa,0x0be6,0xfbf5
|
||||
};
|
||||
int i, ch;
|
||||
|
||||
for (ch = 0; ch < channel_count; ch++) {
|
||||
for (i = 0; i < 16; i++) {
|
||||
vgmstream->ch[ch].adpcm_coef[i] = coef[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* has extra 0x2e coefs before each channel, not counted in data_size */
|
||||
vgmstream->interleave_block_size = (data_size + 0x2e*channel_count) / channel_count;
|
||||
|
||||
dsp_read_coefs_be(vgmstream, streamFile, start_offset+0x00, vgmstream->interleave_block_size);
|
||||
dsp_read_hist_be (vgmstream, streamFile, start_offset+0x20, vgmstream->interleave_block_size);
|
||||
start_offset += 0x2e;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0002: /* PC */
|
||||
if (block_size != 0x24*channel_count)
|
||||
goto fail;
|
||||
vgmstream->coding_type = coding_MSADPCM;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->interleave_block_size = 0x24*channel_count;
|
||||
|
||||
vgmstream->num_samples = msadpcm_bytes_to_samples(data_size, vgmstream->interleave_block_size, channel_count);
|
||||
if (!is_jade_v2) {
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 0x0001: { /* PS3 */
|
||||
VGMSTREAM *temp_vgmstream = NULL;
|
||||
STREAMFILE *temp_streamFile = NULL;
|
||||
|
||||
if (block_size != 0x02*channel_count)
|
||||
goto fail;
|
||||
|
||||
/* a MSF (usually ATRAC3) masquerading as PCM */
|
||||
if (read_32bitBE(start_offset, streamFile) != 0x4D534643) /* "MSF\43" */
|
||||
goto fail;
|
||||
|
||||
temp_streamFile = setup_jade_streamfile(streamFile, start_offset, data_size, "msf");
|
||||
if (!temp_streamFile) goto fail;
|
||||
|
||||
temp_vgmstream = init_vgmstream_ps3_msf(temp_streamFile);
|
||||
close_streamfile(temp_streamFile);
|
||||
if (!temp_vgmstream) goto fail;
|
||||
|
||||
temp_vgmstream->meta_type = vgmstream->meta_type;
|
||||
close_vgmstream(vgmstream);
|
||||
return temp_vgmstream;
|
||||
}
|
||||
|
||||
default: /* X360 uses .XMA */
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* V1 loops by extension, try to detect incorrectly looped jingles (too short) */
|
||||
if (!is_jade_v2) {
|
||||
if(loop_flag
|
||||
&& vgmstream->num_samples < 15*sample_rate) { /* in seconds */
|
||||
vgmstream->loop_flag = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( !vgmstream_open_stream(vgmstream,streamFile,start_offset) )
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* extract loops from "cue /LIST", returns if loops (info from Droolie) */
|
||||
static int get_loop_points(STREAMFILE *streamFile, int *out_loop_start, int *out_loop_end) {
|
||||
off_t cue_offset, list_offset;
|
||||
size_t cue_size, list_size;
|
||||
off_t offset, first_offset = 0x0c;
|
||||
int i, cue_count, loop_id = 0, loop_start = 0, loop_end = 0;
|
||||
|
||||
|
||||
/* unlooped files may contain LIST, but also may not */
|
||||
if (!find_chunk(streamFile, 0x63756520,first_offset,0, &cue_offset,&cue_size, 0, 0)) /* "cue " */
|
||||
goto fail;
|
||||
if (!find_chunk(streamFile, 0x4C495354,first_offset,0, &list_offset,&list_size, 0, 0)) /* "LIST" */
|
||||
goto fail;
|
||||
|
||||
offset = list_offset + 0x04;
|
||||
while (offset < list_offset + list_size) {
|
||||
uint32_t chunk_id = read_32bitBE(offset+0x00, streamFile);
|
||||
uint32_t chunk_size = read_32bitLE(offset+0x04, streamFile);
|
||||
offset += 0x08;
|
||||
|
||||
switch(chunk_id) {
|
||||
case 0x6C61626C: /* "labl" */
|
||||
if (read_32bitBE(offset+0x04, streamFile) == 0x6C6F6F70) /* "loop", actually an string tho */
|
||||
loop_id = read_32bitLE(offset+0x00, streamFile);
|
||||
chunk_size += (chunk_size % 2) ? 1 : 0; /* string is even-padded after size */
|
||||
break;
|
||||
case 0x6C747874: /* "ltxt" */
|
||||
if (loop_id == read_32bitLE(offset+0x00, streamFile))
|
||||
loop_end = read_32bitLE(offset+0x04, streamFile);
|
||||
break;
|
||||
|
||||
default:
|
||||
VGM_LOG("Jade: unknown LIST chunk at %lx\n", offset);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
offset += chunk_size;
|
||||
}
|
||||
|
||||
if (!loop_end)
|
||||
return 0;
|
||||
|
||||
cue_count = read_32bitLE(cue_offset+0x00, streamFile);
|
||||
for (i = 0; i < cue_count; i++) {
|
||||
if (loop_id == read_32bitLE(cue_offset+0x04 + i*0x18 + 0x00, streamFile)) {
|
||||
loop_start = read_32bitLE(cue_offset+0x04 + i*0x18 + 0x04, streamFile);
|
||||
loop_end += loop_start;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*out_loop_start = loop_start;
|
||||
*out_loop_end = loop_end;
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Jade RIFF in containers */
|
||||
VGMSTREAM * init_vgmstream_ubi_jade_container(STREAMFILE *streamFile) {
|
||||
VGMSTREAM *vgmstream = NULL;
|
||||
STREAMFILE *temp_streamFile = NULL;
|
||||
off_t subfile_offset;
|
||||
size_t subfile_size;
|
||||
|
||||
/* Jade packs files in bigfiles, and once extracted the sound files have extra engine data before
|
||||
* the RIFF + padding after. Most extractors don't remove the padding correctly, so here we add support. */
|
||||
|
||||
/* checks */
|
||||
/* standard Jade exts + .xma for padded XMA used in Beyond Good & Evil HD (X360) */
|
||||
if (!check_extensions(streamFile,"waa,wac,wad,wam,wav,lwav,xma"))
|
||||
goto fail;
|
||||
|
||||
if (read_32bitBE(0x04,streamFile) == 0x52494646 &&
|
||||
read_32bitLE(0x00,streamFile)+0x04 == get_streamfile_size(streamFile)) {
|
||||
/* data size + RIFF + padding */
|
||||
subfile_offset = 0x04;
|
||||
}
|
||||
else if (read_32bitBE(0x00,streamFile) == 0x52494646 &&
|
||||
read_32bitLE(0x04,streamFile)+0x04+0x04 < get_streamfile_size(streamFile) &&
|
||||
(get_streamfile_size(streamFile) + 0x04) % 0x800 == 0) {
|
||||
/* RIFF + padding with data size removed (bad extraction) */
|
||||
subfile_offset = 0x00;
|
||||
}
|
||||
else if (read_32bitBE(0x04,streamFile) == 0x52494646 &&
|
||||
read_32bitLE(0x00,streamFile) == get_streamfile_size(streamFile)) {
|
||||
/* data_size + RIFF + padding - 0x04 (bad extraction) */
|
||||
subfile_offset = 0x04;
|
||||
}
|
||||
else {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
subfile_size = read_32bitLE(subfile_offset+0x04,streamFile) + 0x04+0x04;
|
||||
|
||||
temp_streamFile = setup_jade_streamfile(streamFile, subfile_offset,subfile_size, NULL);
|
||||
if (!temp_streamFile) goto fail;
|
||||
|
||||
if (check_extensions(streamFile,"xma")) {
|
||||
vgmstream = init_vgmstream_xma(temp_streamFile);
|
||||
} else {
|
||||
vgmstream = init_vgmstream_ubi_jade(temp_streamFile);
|
||||
}
|
||||
|
||||
close_streamfile(temp_streamFile);
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
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;
|
||||
}
|
293
src/meta/ubi_lyn.c
Normal file
293
src/meta/ubi_lyn.c
Normal file
@ -0,0 +1,293 @@
|
||||
#include "meta.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "ubi_lyn_ogg_streamfile.h"
|
||||
|
||||
static STREAMFILE* setup_lyn_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size);
|
||||
|
||||
/* LyN RIFF - from Ubisoft LyN engine games [Red Steel 2 (Wii), Adventures of Tintin (Multi), From Dust (Multi), Just Dance 3/4 (multi)] */
|
||||
VGMSTREAM * init_vgmstream_ubi_lyn(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset, first_offset = 0xc;
|
||||
off_t fmt_offset, data_offset, fact_offset;
|
||||
size_t fmt_size, data_size, fact_size;
|
||||
int loop_flag, channel_count, sample_rate, codec;
|
||||
int num_samples;
|
||||
|
||||
|
||||
/* checks */
|
||||
/* .sns: Red Steel 2, .wav: Tintin, .son: From Dust */
|
||||
if (!check_extensions(streamFile,"sns,wav,lwav,son"))
|
||||
goto fail;
|
||||
|
||||
/* a slightly eccentric RIFF with custom codecs */
|
||||
if (read_32bitBE(0x00,streamFile) != 0x52494646 || /* "RIFF" */
|
||||
read_32bitBE(0x08,streamFile) != 0x57415645) /* "WAVE" */
|
||||
goto fail;
|
||||
if (read_32bitLE(0x04,streamFile)+0x04+0x04 != get_streamfile_size(streamFile))
|
||||
goto fail;
|
||||
|
||||
if (!find_chunk(streamFile, 0x666d7420,first_offset,0, &fmt_offset,&fmt_size, 0, 0)) /* "fmt " */
|
||||
goto fail;
|
||||
if (!find_chunk(streamFile, 0x64617461,first_offset,0, &data_offset,&data_size, 0, 0)) /* "data" */
|
||||
goto fail;
|
||||
|
||||
/* always found, even with PCM (LyN subchunk seems to contain the engine version, ex. 0x0d/10) */
|
||||
if (!find_chunk(streamFile, 0x66616374,first_offset,0, &fact_offset,&fact_size, 0, 0)) /* "fact" */
|
||||
goto fail;
|
||||
if (fact_size != 0x10 || read_32bitBE(fact_offset+0x04, streamFile) != 0x4C794E20) /* "LyN " */
|
||||
goto fail;
|
||||
num_samples = read_32bitLE(fact_offset+0x00, streamFile);
|
||||
/* sometimes there is a LySE chunk */
|
||||
|
||||
|
||||
/* parse format */
|
||||
{
|
||||
if (fmt_size < 0x12)
|
||||
goto fail;
|
||||
codec = (uint16_t)read_16bitLE(fmt_offset+0x00,streamFile);
|
||||
channel_count = read_16bitLE(fmt_offset+0x02,streamFile);
|
||||
sample_rate = read_32bitLE(fmt_offset+0x04,streamFile);
|
||||
/* 0x08: average bytes, 0x0c: block align, 0x0e: bps, etc */
|
||||
|
||||
/* fake WAVEFORMATEX, used with > 2ch */
|
||||
if (codec == 0xFFFE) {
|
||||
if (fmt_size < 0x28)
|
||||
goto fail;
|
||||
/* fake GUID with first value doubling as codec */
|
||||
codec = read_32bitLE(fmt_offset+0x18,streamFile);
|
||||
if (read_32bitBE(fmt_offset+0x1c,streamFile) != 0x00001000 &&
|
||||
read_32bitBE(fmt_offset+0x20,streamFile) != 0x800000AA &&
|
||||
read_32bitBE(fmt_offset+0x24,streamFile) != 0x00389B71) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* most songs simply repeat, loop if it looks long enough */
|
||||
loop_flag = (num_samples > 20*sample_rate); /* in seconds */
|
||||
start_offset = data_offset;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->meta_type = meta_UBI_LYN;
|
||||
vgmstream->num_samples = num_samples;
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
switch(codec) {
|
||||
case 0x0001: /* PCM */
|
||||
vgmstream->coding_type = coding_PCM16LE; /* LE even in X360 */
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x02;
|
||||
break;
|
||||
|
||||
case 0x5050: /* DSP (Wii) */
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x08;
|
||||
|
||||
/* setup default Ubisoft coefs */
|
||||
{
|
||||
static const int16_t coef[16] = {
|
||||
0x04ab,0xfced,0x0789,0xfedf,0x09a2,0xfae5,0x0c90,0xfac1,
|
||||
0x084d,0xfaa4,0x0982,0xfdf7,0x0af6,0xfafa,0x0be6,0xfbf5
|
||||
};
|
||||
int i, ch;
|
||||
|
||||
for (ch = 0; ch < channel_count; ch++) {
|
||||
for (i = 0; i < 16; i++) {
|
||||
vgmstream->ch[ch].adpcm_coef[i] = coef[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
#ifdef VGM_USE_VORBIS
|
||||
case 0x3157: { /* Ogg (PC), interleaved 1ch */
|
||||
size_t interleave_size, stride_size;
|
||||
layered_layout_data* data = NULL;
|
||||
int i;
|
||||
|
||||
if (read_32bitLE(start_offset+0x00,streamFile) != 1) /* id? */
|
||||
goto fail;
|
||||
|
||||
interleave_size = read_32bitLE(start_offset+0x04,streamFile);
|
||||
stride_size = interleave_size * channel_count;
|
||||
/* interleave is adjusted so there is no smaller last block, it seems */
|
||||
|
||||
vgmstream->coding_type = coding_OGG_VORBIS;
|
||||
vgmstream->layout_type = layout_layered;
|
||||
|
||||
/* init layout */
|
||||
data = init_layout_layered(channel_count);
|
||||
if (!data) goto fail;
|
||||
vgmstream->layout_data = data;
|
||||
|
||||
/* open each layer subfile */
|
||||
for (i = 0; i < channel_count; i++) {
|
||||
STREAMFILE* temp_streamFile = NULL;
|
||||
size_t total_size = read_32bitLE(start_offset+0x08 + 0x04*i,streamFile);
|
||||
off_t layer_offset = start_offset+0x08 + 0x04*channel_count + interleave_size*i;
|
||||
|
||||
temp_streamFile = setup_lyn_ogg_streamfile(streamFile, layer_offset, interleave_size, stride_size, total_size);
|
||||
if (!temp_streamFile) goto fail;
|
||||
|
||||
data->layers[i] = init_vgmstream_ogg_vorbis(temp_streamFile);
|
||||
close_streamfile(temp_streamFile);
|
||||
if (!data->layers[i]) goto fail;
|
||||
|
||||
/* could validate between layers, meh */
|
||||
}
|
||||
|
||||
/* setup layered VGMSTREAMs */
|
||||
if (!setup_layout_layered(data))
|
||||
goto fail;
|
||||
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef VGM_USE_MPEG
|
||||
case 0x5051: { /* MPEG (PS3/PC), interleaved 1ch */
|
||||
mpeg_codec_data *mpeg_data = NULL;
|
||||
mpeg_custom_config cfg = {0};
|
||||
int i;
|
||||
|
||||
if (read_32bitLE(start_offset+0x00,streamFile) != 2) /* id? */
|
||||
goto fail;
|
||||
|
||||
cfg.interleave = read_32bitLE(start_offset+0x04,streamFile);
|
||||
cfg.chunk_size = read_32bitLE(start_offset+0x08,streamFile);
|
||||
/* 0x08: frame size, 0x0c: frame per interleave, 0x10: samples per frame */
|
||||
|
||||
/* skip seek tables and find actual start */
|
||||
start_offset += 0x14;
|
||||
data_size -= 0x14;
|
||||
for (i = 0; i < channel_count; i++) {
|
||||
int entries = read_32bitLE(start_offset,streamFile);
|
||||
|
||||
start_offset += 0x04 + entries*0x08;
|
||||
data_size -= 0x04 + entries*0x08;
|
||||
}
|
||||
|
||||
cfg.data_size = data_size;
|
||||
|
||||
//todo data parsing looks correct but some files decode a bit wrong at the end (ex. Tintin: Music~Boss~Allan~Victory~02)
|
||||
mpeg_data = init_mpeg_custom(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_LYN, &cfg);
|
||||
if (!mpeg_data) goto fail;
|
||||
vgmstream->codec_data = mpeg_data;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
case 0x0166: { /* XMA (X360), standard */
|
||||
uint8_t buf[0x100];
|
||||
int bytes;
|
||||
off_t chunk_offset;
|
||||
size_t chunk_size, seek_size;
|
||||
|
||||
if (read_32bitLE(start_offset+0x00,streamFile) != 3) /* id? */
|
||||
goto fail;
|
||||
|
||||
/* skip standard XMA header + seek table */
|
||||
chunk_offset = start_offset + 0x04 + 0x04;
|
||||
chunk_size = read_32bitLE(start_offset + 0x04, streamFile);
|
||||
seek_size = read_32bitLE(chunk_offset+chunk_size, streamFile);
|
||||
start_offset += (0x04 + 0x04 + chunk_size + 0x04 + seek_size);
|
||||
data_size -= (0x04 + 0x04 + chunk_size + 0x04 + seek_size);
|
||||
|
||||
bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf,0x100, chunk_offset,chunk_size, data_size, streamFile, 1);
|
||||
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;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* LyN RIFF in containers */
|
||||
VGMSTREAM * init_vgmstream_ubi_lyn_container(STREAMFILE *streamFile) {
|
||||
VGMSTREAM *vgmstream = NULL;
|
||||
STREAMFILE *temp_streamFile = NULL;
|
||||
off_t subfile_offset;
|
||||
size_t subfile_size;
|
||||
|
||||
/* LyN packs files in bigfiles, and once extracted the sound files have extra engine
|
||||
* data before the RIFF. Might as well support them in case the RIFF wasn't extracted. */
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile,"sns,wav,lwav,son"))
|
||||
goto fail;
|
||||
|
||||
/* find "RIFF" position */
|
||||
if (read_32bitBE(0x00,streamFile) == 0x4C795345 && /* "LySE" */
|
||||
read_32bitBE(0x14,streamFile) == 0x52494646) { /* "RIFF" */
|
||||
subfile_offset = 0x14; /* Adventures of Tintin */
|
||||
}
|
||||
else if (read_32bitLE(0x00,streamFile)+0x20 == get_streamfile_size(streamFile) &&
|
||||
read_32bitBE(0x20,streamFile) == 0x52494646) { /* "RIFF" */
|
||||
subfile_offset = 0x20; /* Red Steel 2, From Dust */
|
||||
}
|
||||
else {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
subfile_size = read_32bitLE(subfile_offset+0x04,streamFile) + 0x04+0x04;
|
||||
|
||||
temp_streamFile = setup_lyn_streamfile(streamFile, subfile_offset,subfile_size);
|
||||
if (!temp_streamFile) goto fail;
|
||||
|
||||
vgmstream = init_vgmstream_ubi_lyn(temp_streamFile);
|
||||
|
||||
close_streamfile(temp_streamFile);
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static STREAMFILE* setup_lyn_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size) {
|
||||
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;
|
||||
|
||||
return temp_streamFile;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
return NULL;
|
||||
}
|
92
src/meta/ubi_lyn_ogg_streamfile.h
Normal file
92
src/meta/ubi_lyn_ogg_streamfile.h
Normal file
@ -0,0 +1,92 @@
|
||||
#ifndef _LYN_OGG_STREAMFILE_H_
|
||||
#define _LYN_OGG_STREAMFILE_H_
|
||||
#include "../streamfile.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
off_t start_physical_offset; /* interleaved data start, for this substream */
|
||||
size_t interleave_block_size; /* max size that can be read before encountering other substreams */
|
||||
size_t stride_size; /* step size between interleave blocks (interleave*channels) */
|
||||
size_t total_size; /* final size of the deinterleaved substream */
|
||||
} lyn_ogg_io_data;
|
||||
|
||||
|
||||
/* Handles deinterleaving of complete files, skipping portions or other substreams. */
|
||||
static size_t scd_dsp_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, lyn_ogg_io_data* data) {
|
||||
size_t total_read = 0;
|
||||
|
||||
while (length > 0) {
|
||||
size_t to_read;
|
||||
size_t length_available;
|
||||
off_t block_num;
|
||||
off_t intrablock_offset;
|
||||
off_t physical_offset;
|
||||
|
||||
block_num = offset / data->interleave_block_size;
|
||||
intrablock_offset = offset % data->interleave_block_size;
|
||||
physical_offset = data->start_physical_offset + block_num*data->stride_size + intrablock_offset;
|
||||
length_available = data->interleave_block_size - intrablock_offset;
|
||||
|
||||
if (length < length_available) {
|
||||
to_read = length;
|
||||
}
|
||||
else {
|
||||
to_read = length_available;
|
||||
}
|
||||
|
||||
if (to_read > 0) {
|
||||
size_t bytes_read;
|
||||
|
||||
bytes_read = read_streamfile(dest, physical_offset, to_read, streamfile);
|
||||
total_read += bytes_read;
|
||||
|
||||
if (bytes_read != to_read) {
|
||||
return total_read;
|
||||
}
|
||||
|
||||
dest += bytes_read;
|
||||
offset += bytes_read;
|
||||
length -= bytes_read;
|
||||
}
|
||||
}
|
||||
|
||||
return total_read;
|
||||
}
|
||||
|
||||
static size_t scd_dsp_io_size(STREAMFILE *streamfile, lyn_ogg_io_data* data) {
|
||||
return data->total_size;
|
||||
}
|
||||
|
||||
|
||||
static STREAMFILE* setup_lyn_ogg_streamfile(STREAMFILE *streamFile, off_t start_offset, size_t interleave_block_size, size_t stride_size, size_t total_size) {
|
||||
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||
lyn_ogg_io_data io_data = {0};
|
||||
size_t io_data_size = sizeof(lyn_ogg_io_data);
|
||||
|
||||
io_data.start_physical_offset = start_offset;
|
||||
io_data.interleave_block_size = interleave_block_size;
|
||||
io_data.stride_size = stride_size;
|
||||
io_data.total_size = total_size;
|
||||
|
||||
|
||||
/* setup subfile */
|
||||
new_streamFile = open_wrap_streamfile(streamFile);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, scd_dsp_io_read,scd_dsp_io_size);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_fakename_streamfile(temp_streamFile, NULL,"ogg");
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
return temp_streamFile;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* _LYN_OGG_STREAMFILE_H_ */
|
@ -1,182 +0,0 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/*
|
||||
const short wad_coef[16][2] =
|
||||
{
|
||||
{0x4002,0x2003},
|
||||
{0x2016,0xc600},
|
||||
{0xC600,0x98ab},
|
||||
{0x96bf,0x29c5},
|
||||
{0x2003,0x0081},
|
||||
{0x0e00,0x2004},
|
||||
{0x8e01,0xc500},
|
||||
{0x70bf,0x8128},
|
||||
{0x288e,0xc600},
|
||||
{0x016e,0x0e5b},
|
||||
{0xbe20,0x2003},
|
||||
{0x03c6,0xc600},
|
||||
{0x0048,0xe85a},
|
||||
{0xbe28,0x28c6},
|
||||
{0xc600,0x00F6},
|
||||
{0xbeab,0x5520}
|
||||
};*/
|
||||
const short wad_coef[16] =
|
||||
{
|
||||
0x04ab, 0xfced,
|
||||
0x0789, 0xfedf,
|
||||
0x09a2, 0xfae5,
|
||||
0x0c90, 0xfac1,
|
||||
0x084d, 0xfaa4,
|
||||
0x0982, 0xfdf7,
|
||||
0x0af6, 0xfafa,
|
||||
0x0be6, 0xfbf5
|
||||
};
|
||||
|
||||
|
||||
/* WAC/WAD/WAM/WAA - from Beyond Good & Evil (PS2/Xbox/GC/Wii) */
|
||||
VGMSTREAM * init_vgmstream_waa_wac_wad_wam(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
int i;
|
||||
off_t start_offset;
|
||||
int loop_flag;
|
||||
int channel_count;
|
||||
int coef1_start;
|
||||
int coef2_start;
|
||||
int second_channel_start = -1;
|
||||
|
||||
// Check file extensions
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("waa",filename_extension(filename)) &&
|
||||
strcasecmp("wac",filename_extension(filename)) &&
|
||||
strcasecmp("wad",filename_extension(filename)) &&
|
||||
strcasecmp("wam",filename_extension(filename))) goto fail;
|
||||
|
||||
/* check header */
|
||||
if (read_32bitBE(0x00,streamFile) != 0x52494646 || /* "RIFF" */
|
||||
read_32bitBE(0x08,streamFile) != 0x57415645 || /* "WAVE" */
|
||||
read_32bitBE(0x0C,streamFile) != 0x666D7420 || /* "fmt " */
|
||||
read_32bitBE(0x10,streamFile) != 0x12000000) /* "0x12000000" */
|
||||
goto fail;
|
||||
|
||||
/* files don't contain looping information,
|
||||
so the looping is not done depending on extension.
|
||||
wam and waa contain ambient sounds and music, so often they contain
|
||||
looped music. Change extension to wac or wad to make the sound non-looping.
|
||||
*/
|
||||
loop_flag = strcasecmp("wac",filename_extension(filename)) &&
|
||||
strcasecmp("wad",filename_extension(filename));
|
||||
channel_count = (uint16_t)read_16bitLE(0x16,streamFile);
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* Check what encoder is needed */
|
||||
//FIXME: //PC version uses pcm, but which encoder?
|
||||
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = read_32bitLE(0x18,streamFile);
|
||||
vgmstream->meta_type = meta_WAA_WAC_WAD_WAM;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
switch((uint16_t)read_16bitLE(0x14,streamFile)) {
|
||||
case 0x0069: // XBOX IMA ADPCM
|
||||
start_offset = 0x2E;
|
||||
vgmstream->coding_type = coding_XBOX_IMA;
|
||||
vgmstream->num_samples = xbox_ima_bytes_to_samples(read_32bitLE(0x2A,streamFile), channel_count);
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = xbox_ima_bytes_to_samples(read_32bitLE(0x2A,streamFile),channel_count);
|
||||
}
|
||||
break;
|
||||
case 0xFFFF: // PS2 ADPCM
|
||||
start_offset = 0x2E;
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->num_samples = (read_32bitLE(0x2A,streamFile))/16*28/channel_count;
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = (read_32bitLE(0x2A,streamFile))/16*28/channel_count;
|
||||
}
|
||||
second_channel_start = (read_32bitLE(0x2A,streamFile)/2)+start_offset;
|
||||
break;
|
||||
case 0xFFFE: // GameCube/WII DSP
|
||||
start_offset = 0x5C;
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->num_samples = (read_32bitLE(0x2A,streamFile))*14/8/channel_count;
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = (read_32bitLE(0x2A,streamFile))*14/8/channel_count;
|
||||
}
|
||||
if(read_16bitLE(0x24,streamFile)==0x00)//is a wii file with no coeff table
|
||||
{
|
||||
//FIXME: WII version of WAM/WAD/WAC need some coeff table from somewhere
|
||||
for (i=0;i<16;i++)
|
||||
vgmstream->ch[0].adpcm_coef[i] = wad_coef[i];
|
||||
if (channel_count == 2) {
|
||||
for (i=0;i<16;i++)
|
||||
vgmstream->ch[1].adpcm_coef[i] = wad_coef[i];
|
||||
}
|
||||
goto fail;
|
||||
}
|
||||
else
|
||||
{
|
||||
second_channel_start = (read_32bitLE(0x2A,streamFile)/2)+0x8A;
|
||||
/* Retrieveing the coef tables */
|
||||
coef1_start = 0x2E;
|
||||
coef2_start = (read_32bitLE(0x2A,streamFile)/2)+0x5C;
|
||||
|
||||
{
|
||||
int i;
|
||||
for (i=0;i<16;i++)
|
||||
vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(coef1_start+i*2,streamFile);
|
||||
if (channel_count == 2) {
|
||||
for (i=0;i<16;i++)
|
||||
vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(coef2_start+i*2,streamFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* 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;
|
||||
|
||||
if (vgmstream->coding_type == coding_XBOX_IMA) {
|
||||
/* xbox interleaving is a little odd */
|
||||
vgmstream->ch[i].channel_start_offset=start_offset;
|
||||
} else {
|
||||
vgmstream->ch[0].channel_start_offset=start_offset;
|
||||
if (channel_count == 2) {
|
||||
if (second_channel_start == -1) goto fail;
|
||||
vgmstream->ch[1].channel_start_offset=second_channel_start;
|
||||
}
|
||||
}
|
||||
vgmstream->ch[i].offset = vgmstream->ch[i].channel_start_offset;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
/* clean up anything we may have opened */
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -78,6 +78,18 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ignore LyN RIFF */
|
||||
{
|
||||
off_t fact_offset;
|
||||
size_t fact_size;
|
||||
|
||||
if (find_chunk(streamFile, 0x66616374,first_offset,0, &fact_offset,&fact_size, 0, 0)) { /* "fact" */
|
||||
if (fact_size == 0x10 && read_32bitBE(fact_offset+0x04, streamFile) == 0x4C794E20) /* "LyN " */
|
||||
goto fail; /* parsed elsewhere */
|
||||
/* Wwise doesn't use "fact", though */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* parse format (roughly spec-compliant but some massaging is needed) */
|
||||
{
|
||||
|
@ -119,7 +119,6 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
|
||||
init_vgmstream_scd_pcm,
|
||||
init_vgmstream_ps2_pcm,
|
||||
init_vgmstream_ps2_rkv,
|
||||
init_vgmstream_ps2_psw,
|
||||
init_vgmstream_ps2_vas,
|
||||
init_vgmstream_ps2_tec,
|
||||
init_vgmstream_ps2_enth,
|
||||
@ -178,7 +177,8 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
|
||||
init_vgmstream_bgw,
|
||||
init_vgmstream_spw,
|
||||
init_vgmstream_ps2_ass,
|
||||
init_vgmstream_waa_wac_wad_wam,
|
||||
init_vgmstream_ubi_jade,
|
||||
init_vgmstream_ubi_jade_container,
|
||||
init_vgmstream_seg,
|
||||
init_vgmstream_nds_strm_ffta2,
|
||||
init_vgmstream_str_asr,
|
||||
@ -394,6 +394,9 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
|
||||
init_vgmstream_sthd,
|
||||
init_vgmstream_pcm_sre,
|
||||
init_vgmstream_dsp_mcadpcm,
|
||||
init_vgmstream_ubi_lyn,
|
||||
init_vgmstream_ubi_lyn_container,
|
||||
init_vgmstream_msb_msh,
|
||||
|
||||
init_vgmstream_txth, /* should go at the end (lower priority) */
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
@ -2386,11 +2389,6 @@ static STREAMFILE * get_vgmstream_average_bitrate_channel_streamfile(VGMSTREAM *
|
||||
{
|
||||
//AAX, AIX?
|
||||
|
||||
if (vgmstream->layout_type==layout_layered) {
|
||||
layered_layout_data *data = (layered_layout_data *) vgmstream->layout_data;
|
||||
return data->layers[channel]->ch[0].streamfile;
|
||||
}
|
||||
|
||||
if (vgmstream->coding_type==coding_NWA) {
|
||||
nwa_codec_data *data = (nwa_codec_data *) vgmstream->codec_data;
|
||||
if (data && data->nwa)
|
||||
@ -2461,6 +2459,11 @@ int get_vgmstream_average_bitrate(VGMSTREAM * vgmstream) {
|
||||
segmented_layout_data *data = (segmented_layout_data *) vgmstream->layout_data;
|
||||
return get_vgmstream_average_bitrate(data->segments[0]);
|
||||
}
|
||||
if (vgmstream->layout_type==layout_layered) {
|
||||
layered_layout_data *data = (layered_layout_data *) vgmstream->layout_data;
|
||||
return get_vgmstream_average_bitrate(data->layers[0]);
|
||||
}
|
||||
|
||||
|
||||
channels = get_vgmstream_average_bitrate_channel_count(vgmstream);
|
||||
if (!channels) return 0;
|
||||
|
@ -373,7 +373,6 @@ typedef enum {
|
||||
meta_SCD_PCM, /* Lunar - Eternal Blue */
|
||||
meta_PS2_PCM, /* Konami KCEJ East: Ephemeral Fantasia, Yu-Gi-Oh! The Duelists of the Roses, 7 Blades */
|
||||
meta_PS2_RKV, /* Legacy of Kain - Blood Omen 2 (PS2) */
|
||||
meta_PS2_PSW, /* Rayman Raving Rabbids */
|
||||
meta_PS2_VAS, /* Pro Baseball Spirits 5 */
|
||||
meta_PS2_TEC, /* TECMO badflagged stream */
|
||||
meta_PS2_ENTH, /* Enthusia */
|
||||
@ -395,13 +394,11 @@ typedef enum {
|
||||
meta_GSP_GSB, /* Tecmo games (Super Swing Golf 1 & 2, Quamtum Theory) */
|
||||
meta_YDSP, /* WWE Day of Reckoning */
|
||||
meta_FFCC_STR, /* Final Fantasy: Crystal Chronicles */
|
||||
|
||||
meta_WAA_WAC_WAD_WAM, /* Beyond Good & Evil */
|
||||
meta_UBI_JADE, /* Beyond Good & Evil, Rayman Raving Rabbids */
|
||||
meta_GCA, /* Metal Slug Anthology */
|
||||
meta_MSVP, /* Popcap Hits */
|
||||
meta_NGC_SSM, /* Golden Gashbell Full Power */
|
||||
meta_PS2_JOE, /* Wall-E / Pixar games */
|
||||
|
||||
meta_NGC_YMF, /* WWE WrestleMania X8 */
|
||||
meta_SADL, /* .sad */
|
||||
meta_PS2_CCC, /* Tokyo Xtreme Racer DRIFT 2 */
|
||||
@ -479,7 +476,6 @@ typedef enum {
|
||||
meta_RIFF_WAVE_smpl, /* RIFF w/ loop data in smpl chunk */
|
||||
meta_RIFF_WAVE_wsmp, /* RIFF w/ loop data in wsmp chunk */
|
||||
meta_RIFF_WAVE_MWV, /* .mwv RIFF w/ loop data in ctrl chunk pflt */
|
||||
meta_RIFF_WAVE_SNS, /* .sns RIFF */
|
||||
meta_RIFX_WAVE, /* RIFX, for big-endian WAVs */
|
||||
meta_RIFX_WAVE_smpl, /* RIFX w/ loop data in smpl chunk */
|
||||
meta_XNB, /* XNA Game Studio 4.0 */
|
||||
@ -668,6 +664,9 @@ typedef enum {
|
||||
meta_MP4, /* MP4/AAC */
|
||||
meta_PCM_SRE, /* .PCM+SRE [Viewtiful Joe (PS2)] */
|
||||
meta_DSP_MCADPCM, /* Skyrim (Switch) */
|
||||
meta_UBI_LYN, /* Ubisoft LyN engine [The Adventures of Tintin (multi)] */
|
||||
meta_MSB_MSH, /* sfx companion of MIH+MIB */
|
||||
meta_OGG_RPGMV, /* Ogg Vorbis with encryption [RPG Maker MV games (PC)] */
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
meta_FFmpeg,
|
||||
@ -886,6 +885,8 @@ typedef struct {
|
||||
off_t block_offset;
|
||||
size_t block_size;
|
||||
|
||||
int prev_block_samples; /* count for optimization */
|
||||
|
||||
} vorbis_custom_codec_data;
|
||||
#endif
|
||||
|
||||
@ -967,6 +968,7 @@ typedef struct {
|
||||
mpeg_custom_t type; /* mpeg subtype */
|
||||
mpeg_custom_config config; /* config depending on the mode */
|
||||
|
||||
size_t default_buffer_size;
|
||||
mpeg_custom_stream **streams; /* array of MPEG streams (ex. 2ch+2ch) */
|
||||
size_t streams_size;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user