mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-17 23:36:41 +01:00
Parse "wsmp" loop chunk, rarely found in Xbox games [Dynasty Warriors 5]
This commit is contained in:
parent
3579858ef4
commit
aca3dc5f2d
@ -700,6 +700,7 @@ static const meta_info meta_info_list[] = {
|
|||||||
{meta_PS2_PSH, "Dawn of Mana - Seiken Densetsu 4 PSH Header"},
|
{meta_PS2_PSH, "Dawn of Mana - Seiken Densetsu 4 PSH Header"},
|
||||||
{meta_RIFF_WAVE_labl, "RIFF WAVE header with loop markers"},
|
{meta_RIFF_WAVE_labl, "RIFF WAVE header with loop markers"},
|
||||||
{meta_RIFF_WAVE_smpl, "RIFF WAVE header with sample looping info"},
|
{meta_RIFF_WAVE_smpl, "RIFF WAVE header with sample looping info"},
|
||||||
|
{meta_RIFF_WAVE_wsmp, "RIFF WAVE header with wsmp looping info"},
|
||||||
{meta_RIFX_WAVE, "RIFX WAVE header"},
|
{meta_RIFX_WAVE, "RIFX WAVE header"},
|
||||||
{meta_RIFX_WAVE_smpl, "RIFX WAVE header with sample looping info"},
|
{meta_RIFX_WAVE_smpl, "RIFX WAVE header with sample looping info"},
|
||||||
{meta_XNB, "Microsoft XNA Game Studio 4.0 header"},
|
{meta_XNB, "Microsoft XNA Game Studio 4.0 header"},
|
||||||
|
@ -232,10 +232,9 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
|||||||
int fact_sample_skip = 0;
|
int fact_sample_skip = 0;
|
||||||
|
|
||||||
int loop_flag = 0;
|
int loop_flag = 0;
|
||||||
long loop_start_ms = -1;
|
int loop_start_sample = 0, loop_end_sample = 0;
|
||||||
long loop_end_ms = -1;
|
long loop_start_ms = -1, loop_end_ms = -1;
|
||||||
off_t loop_start_offset = -1;
|
off_t loop_start_offset = -1, loop_end_offset = -1;
|
||||||
off_t loop_end_offset = -1;
|
|
||||||
|
|
||||||
int FormatChunkFound = 0, DataChunkFound = 0, JunkFound = 0;
|
int FormatChunkFound = 0, DataChunkFound = 0, JunkFound = 0;
|
||||||
|
|
||||||
@ -296,12 +295,11 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
|||||||
if (fmt.codec == 0x6771 && chunk_type == 0x64617461) /* Liar-soft again */
|
if (fmt.codec == 0x6771 && chunk_type == 0x64617461) /* Liar-soft again */
|
||||||
chunk_size += (chunk_size%2) ? 0x01 : 0x00;
|
chunk_size += (chunk_size%2) ? 0x01 : 0x00;
|
||||||
|
|
||||||
if (current_chunk+8+chunk_size > file_size) goto fail;
|
if (current_chunk+0x08+chunk_size > file_size) goto fail;
|
||||||
|
|
||||||
switch(chunk_type) {
|
switch(chunk_type) {
|
||||||
case 0x666d7420: /* "fmt " */
|
case 0x666d7420: /* "fmt " */
|
||||||
/* only one per file */
|
if (FormatChunkFound) goto fail; /* only one per file */
|
||||||
if (FormatChunkFound) goto fail;
|
|
||||||
FormatChunkFound = 1;
|
FormatChunkFound = 1;
|
||||||
|
|
||||||
if (-1 == read_fmt(0, /* big endian == false*/
|
if (-1 == read_fmt(0, /* big endian == false*/
|
||||||
@ -311,20 +309,20 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
|||||||
sns,
|
sns,
|
||||||
mwv))
|
mwv))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 0x64617461: /* data */
|
|
||||||
/* at most one per file */
|
case 0x64617461: /* "data" */
|
||||||
if (DataChunkFound) goto fail;
|
if (DataChunkFound) goto fail; /* only one per file */
|
||||||
DataChunkFound = 1;
|
DataChunkFound = 1;
|
||||||
|
|
||||||
start_offset = current_chunk + 8;
|
start_offset = current_chunk + 0x08;
|
||||||
data_size = chunk_size;
|
data_size = chunk_size;
|
||||||
break;
|
break;
|
||||||
case 0x4C495354: /* LIST */
|
|
||||||
|
case 0x4C495354: /* "LIST" */
|
||||||
/* what lurks within?? */
|
/* what lurks within?? */
|
||||||
switch (read_32bitBE(current_chunk + 8, streamFile)) {
|
switch (read_32bitBE(current_chunk+0x08, streamFile)) {
|
||||||
case 0x6164746C: /* adtl */
|
case 0x6164746C: /* "adtl" */
|
||||||
/* yay, atdl is its own little world */
|
/* yay, atdl is its own little world */
|
||||||
parse_adtl(current_chunk + 8, chunk_size,
|
parse_adtl(current_chunk + 8, chunk_size,
|
||||||
streamFile,
|
streamFile,
|
||||||
@ -334,28 +332,40 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x736D706C: /* smpl */
|
|
||||||
/* check loop count and loop info */
|
case 0x736D706C: /* "smpl" (RIFFMIDISample + MIDILoop chunk) */
|
||||||
if (read_32bitLE(current_chunk+0x24, streamFile)==1) {
|
/* check loop count/loop info (most common) *///todo double check values
|
||||||
if (read_32bitLE(current_chunk+0x2c+4, streamFile)==0) {
|
/* 0x00: manufacturer id, 0x04: product id, 0x08: sample period, 0x0c: unity node,
|
||||||
|
* 0x10: pitch fraction, 0x14: SMPTE format, 0x18: SMPTE offset, 0x1c: loop count, 0x20: sampler data */
|
||||||
|
if (read_32bitLE(current_chunk+0x08+0x1c, streamFile)==1) {
|
||||||
|
/* 0x24: cue point id, 0x28: type (0=forward, 1=alternating, 2=backward)
|
||||||
|
* 0x2c: start, 0x30: end, 0x34: fraction, 0x38: play count */
|
||||||
|
if (read_32bitLE(current_chunk+0x08+0x28, streamFile)==0) {
|
||||||
loop_flag = 1;
|
loop_flag = 1;
|
||||||
loop_start_offset = read_32bitLE(current_chunk+0x2c+8, streamFile);
|
loop_start_offset = read_32bitLE(current_chunk+0x08+0x2c, streamFile);
|
||||||
loop_end_offset = read_32bitLE(current_chunk+0x2c+0xc,streamFile);
|
loop_end_offset = read_32bitLE(current_chunk+0x08+0x30, streamFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x70666c74: /* pflt */
|
|
||||||
if (!mwv) break; /* ignore if not in an mwv */
|
|
||||||
|
|
||||||
mwv_pflt_offset = current_chunk; /* predictor filters */
|
case 0x77736D70: /* "wsmp" (RIFFDLSSample + DLSLoop chunk) */
|
||||||
|
/* check loop count/info (found in some Xbox games: Halo (non-looping), Dynasty Warriors 3, Crimson Sea) */
|
||||||
|
/* 0x00: size, 0x04: unity note, 0x06: fine tune, 0x08: gain, 0x10: loop count */
|
||||||
|
if (chunk_size >= 0x24
|
||||||
|
&& read_32bitLE(current_chunk+0x08+0x00, streamFile) == 0x14
|
||||||
|
&& read_32bitLE(current_chunk+0x08+0x10, streamFile) > 0
|
||||||
|
&& read_32bitLE(current_chunk+0x08+0x14, streamFile) == 0x10) {
|
||||||
|
/* 0x14: size, 0x18: loop type (0=forward, 1=release), 0x1c: loop start, 0x20: loop length */
|
||||||
|
if (read_32bitLE(current_chunk+0x08+0x18, streamFile)==0) {
|
||||||
|
loop_flag = 1;
|
||||||
|
loop_start_sample = read_32bitLE(current_chunk+0x08+0x1c, streamFile);
|
||||||
|
loop_end_sample = read_32bitLE(current_chunk+0x08+0x20, streamFile);
|
||||||
|
loop_end_sample += loop_start_sample;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 0x6374726c: /* ctrl */
|
|
||||||
if (!mwv) break;
|
|
||||||
|
|
||||||
loop_flag = read_32bitLE(current_chunk+0x08, streamFile);
|
case 0x66616374: /* "fact" */
|
||||||
mwv_ctrl_offset = current_chunk;
|
|
||||||
break;
|
|
||||||
case 0x66616374: /* fact */
|
|
||||||
if (chunk_size == 0x04) { /* standard, usually found with ADPCM */
|
if (chunk_size == 0x04) { /* standard, usually found with ADPCM */
|
||||||
fact_sample_count = read_32bitLE(current_chunk+0x08, streamFile);
|
fact_sample_count = read_32bitLE(current_chunk+0x08, streamFile);
|
||||||
} else if (sns && chunk_size == 0x10) {
|
} else if (sns && chunk_size == 0x10) {
|
||||||
@ -367,11 +377,22 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
|||||||
fact_sample_count = read_32bitLE(current_chunk+0x08, streamFile);
|
fact_sample_count = read_32bitLE(current_chunk+0x08, streamFile);
|
||||||
fact_sample_skip = read_32bitLE(current_chunk+0x10, streamFile);
|
fact_sample_skip = read_32bitLE(current_chunk+0x10, streamFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 0x4A554E4B: /* JUNK */
|
|
||||||
|
case 0x70666c74: /* "pflt" (.mwv extension) */
|
||||||
|
if (!mwv) break; /* ignore if not in an mwv */
|
||||||
|
mwv_pflt_offset = current_chunk; /* predictor filters */
|
||||||
|
break;
|
||||||
|
case 0x6374726c: /* "ctrl" (.mwv extension) */
|
||||||
|
if (!mwv) break;
|
||||||
|
loop_flag = read_32bitLE(current_chunk+0x08, streamFile);
|
||||||
|
mwv_ctrl_offset = current_chunk;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x4A554E4B: /* "JUNK" */
|
||||||
JunkFound = 1;
|
JunkFound = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* ignorance is bliss */
|
/* ignorance is bliss */
|
||||||
break;
|
break;
|
||||||
@ -383,7 +404,7 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
|||||||
|
|
||||||
if (!FormatChunkFound || !DataChunkFound) goto fail;
|
if (!FormatChunkFound || !DataChunkFound) goto fail;
|
||||||
|
|
||||||
//todo improve detection using fmt sizes/values as Wwise's don't match the RIFF standard
|
//todo improve detection using fmt sizes/values as Wwise's don't match the RIFF standard
|
||||||
/* JUNK is an optional Wwise chunk, and Wwise hijacks the MSADPCM/MS_IMA/XBOX IMA ids (how nice).
|
/* JUNK is an optional Wwise chunk, and Wwise hijacks the MSADPCM/MS_IMA/XBOX IMA ids (how nice).
|
||||||
* To ensure their stuff is parsed in wwise.c we reject their JUNK, which they put almost always.
|
* To ensure their stuff is parsed in wwise.c we reject their JUNK, which they put almost always.
|
||||||
* As JUNK is legal (if unusual) we only reject those codecs.
|
* As JUNK is legal (if unusual) we only reject those codecs.
|
||||||
@ -579,6 +600,11 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
|||||||
vgmstream->loop_end_sample = loop_end_offset;
|
vgmstream->loop_end_sample = loop_end_offset;
|
||||||
vgmstream->meta_type = meta_RIFF_WAVE_smpl;
|
vgmstream->meta_type = meta_RIFF_WAVE_smpl;
|
||||||
}
|
}
|
||||||
|
else if (loop_start_sample >= 0) {
|
||||||
|
vgmstream->loop_start_sample = loop_start_sample;
|
||||||
|
vgmstream->loop_end_sample = loop_end_sample;
|
||||||
|
vgmstream->meta_type = meta_RIFF_WAVE_wsmp;
|
||||||
|
}
|
||||||
else if (mwv && mwv_ctrl_offset != -1) {
|
else if (mwv && mwv_ctrl_offset != -1) {
|
||||||
vgmstream->loop_start_sample = read_32bitLE(mwv_ctrl_offset+12, streamFile);
|
vgmstream->loop_start_sample = read_32bitLE(mwv_ctrl_offset+12, streamFile);
|
||||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||||
|
@ -481,6 +481,7 @@ typedef enum {
|
|||||||
meta_RIFF_WAVE_POS, /* .wav + .pos for looping (Ys Complete PC) */
|
meta_RIFF_WAVE_POS, /* .wav + .pos for looping (Ys Complete PC) */
|
||||||
meta_RIFF_WAVE_labl, /* RIFF w/ loop Markers in LIST-adtl-labl */
|
meta_RIFF_WAVE_labl, /* RIFF w/ loop Markers in LIST-adtl-labl */
|
||||||
meta_RIFF_WAVE_smpl, /* RIFF w/ loop data in smpl chunk */
|
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_MWV, /* .mwv RIFF w/ loop data in ctrl chunk pflt */
|
||||||
meta_RIFF_WAVE_SNS, /* .sns RIFF */
|
meta_RIFF_WAVE_SNS, /* .sns RIFF */
|
||||||
meta_RIFX_WAVE, /* RIFX, for big-endian WAVs */
|
meta_RIFX_WAVE, /* RIFX, for big-endian WAVs */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user