mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-02-05 06:05:26 +01:00
Fix some .zsd [Dave Mirra Freestyle BMX (PS1/PS2)]
This commit is contained in:
parent
c003ad56bb
commit
bb185027ed
163
src/meta/zsnd.c
163
src/meta/zsnd.c
@ -4,29 +4,29 @@
|
|||||||
|
|
||||||
|
|
||||||
/* ZSND - Z-Axis/Vicarious Visions games [X-Men Legends II (multi), Marvel Ultimate Alliance (multi)] */
|
/* ZSND - Z-Axis/Vicarious Visions games [X-Men Legends II (multi), Marvel Ultimate Alliance (multi)] */
|
||||||
VGMSTREAM * init_vgmstream_zsnd(STREAMFILE *streamFile) {
|
VGMSTREAM* init_vgmstream_zsnd(STREAMFILE* sf) {
|
||||||
VGMSTREAM * vgmstream = NULL;
|
VGMSTREAM* vgmstream = NULL;
|
||||||
STREAMFILE *temp_streamFile = NULL;
|
STREAMFILE* temp_sf = NULL;
|
||||||
off_t start_offset, name_offset;
|
uint32_t start_offset, name_offset, stream_size, name_size;
|
||||||
size_t stream_size, name_size;
|
int loop_flag, channels, sample_rate, layers, layers2 = 0;
|
||||||
int loop_flag, channel_count, sample_rate, layers, layers2 = 0;
|
|
||||||
uint32_t codec;
|
uint32_t codec;
|
||||||
int total_subsongs, target_subsong = streamFile->stream_index;
|
int total_subsongs, target_subsong = sf->stream_index;
|
||||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
|
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
|
||||||
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
|
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
|
||||||
|
|
||||||
|
|
||||||
/* checks */
|
/* checks */
|
||||||
|
if (!is_id32be(0x00,sf, "ZSND"))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
/* .zss/zsm: standard
|
/* .zss/zsm: standard
|
||||||
* .ens/enm: same for PS2
|
* .ens/enm: same for PS2
|
||||||
* .zsd: normal or compact [BMX XXX (Xbox), Aggresive Inline (Xbox)] */
|
* .zsd: normal or compact [BMX XXX (Xbox), Aggresive Inline (Xbox), Dave Mirra Freestyle BMX (PS1/PS2)] */
|
||||||
if (!check_extensions(streamFile, "zss,zsm,ens,enm,zsd"))
|
if (!check_extensions(sf, "zss,zsm,ens,enm,zsd"))
|
||||||
goto fail;
|
return NULL;
|
||||||
if (read_32bitBE(0x00,streamFile) != 0x5A534E44) /* "ZSND" */
|
|
||||||
goto fail;
|
|
||||||
/* probably zss=stream, zsm=memory; no diffs other than size */
|
/* probably zss=stream, zsm=memory; no diffs other than size */
|
||||||
|
|
||||||
codec = read_32bitBE(0x04,streamFile);
|
codec = read_u32be(0x04,sf);
|
||||||
/* 0x08: file size, but slightly bigger (+0x01~04) in some platforms */
|
/* 0x08: file size, but slightly bigger (+0x01~04) in some platforms */
|
||||||
/* 0x0c: header end/first stream start (unneeded as all offsets are absolute) */
|
/* 0x0c: header end/first stream start (unneeded as all offsets are absolute) */
|
||||||
|
|
||||||
@ -42,9 +42,9 @@ VGMSTREAM * init_vgmstream_zsnd(STREAMFILE *streamFile) {
|
|||||||
|
|
||||||
/* parse header tables */
|
/* parse header tables */
|
||||||
{
|
{
|
||||||
off_t header2_offset, header3_offset;
|
uint32_t header2_offset, header3_offset;
|
||||||
int table2_entries, table3_entries;
|
int table2_entries, table3_entries;
|
||||||
off_t table2_body, table3_body;
|
uint32_t table2_body, table3_body;
|
||||||
int is_v1, i;
|
int is_v1, i;
|
||||||
|
|
||||||
|
|
||||||
@ -68,28 +68,28 @@ VGMSTREAM * init_vgmstream_zsnd(STREAMFILE *streamFile) {
|
|||||||
* table1 may have more entries than table2/3, and sometimes isn't set
|
* table1 may have more entries than table2/3, and sometimes isn't set
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* V1 has no table heads, rare [Aggresive Inline (Xbox)]
|
/* V1 has no table heads, rare [Aggresive Inline (Xbox), Dave Mirra Freestyle BMX (PS1/PS2)]
|
||||||
* no apparent flag but we can test if table heads offsets appear */
|
* no apparent flag but we can test if table heads offsets appear */
|
||||||
is_v1 = read_32bit(0x14,streamFile) <= read_32bit(0x1c,streamFile) &&
|
is_v1 = read_32bit(0x14,sf) <= read_32bit(0x1c,sf) &&
|
||||||
read_32bit(0x1c,streamFile) <= read_32bit(0x24,streamFile) &&
|
read_32bit(0x1c,sf) <= read_32bit(0x24,sf) &&
|
||||||
read_32bit(0x24,streamFile) <= read_32bit(0x2c,streamFile) &&
|
read_32bit(0x24,sf) <= read_32bit(0x2c,sf) &&
|
||||||
read_32bit(0x2c,streamFile) <= read_32bit(0x34,streamFile) &&
|
read_32bit(0x2c,sf) <= read_32bit(0x34,sf) &&
|
||||||
read_32bit(0x34,streamFile) <= read_32bit(0x3c,streamFile) &&
|
read_32bit(0x34,sf) <= read_32bit(0x3c,sf) &&
|
||||||
read_32bit(0x3c,streamFile) <= read_32bit(0x44,streamFile);
|
read_32bit(0x3c,sf) <= read_32bit(0x44,sf);
|
||||||
|
|
||||||
if (!is_v1) {
|
if (!is_v1) {
|
||||||
table2_entries = read_32bit(0x1c,streamFile);
|
table2_entries = read_32bit(0x1c,sf);
|
||||||
table2_body = read_32bit(0x24,streamFile);
|
table2_body = read_32bit(0x24,sf);
|
||||||
|
|
||||||
table3_entries = read_32bit(0x28,streamFile);
|
table3_entries = read_32bit(0x28,sf);
|
||||||
table3_body = read_32bit(0x30,streamFile);
|
table3_body = read_32bit(0x30,sf);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
table2_entries = read_32bit(0x18,streamFile);
|
table2_entries = read_32bit(0x18,sf);
|
||||||
table2_body = read_32bit(0x1C,streamFile);
|
table2_body = read_32bit(0x1C,sf);
|
||||||
|
|
||||||
table3_entries = read_32bit(0x20,streamFile);
|
table3_entries = read_32bit(0x20,sf);
|
||||||
table3_body = read_32bit(0x24,streamFile);
|
table3_body = read_32bit(0x24,sf);
|
||||||
}
|
}
|
||||||
|
|
||||||
total_subsongs = table3_entries;
|
total_subsongs = table3_entries;
|
||||||
@ -102,23 +102,23 @@ VGMSTREAM * init_vgmstream_zsnd(STREAMFILE *streamFile) {
|
|||||||
if (table2_entries == 0) goto fail;
|
if (table2_entries == 0) goto fail;
|
||||||
|
|
||||||
header2_offset = table2_body + 0x18*(target_subsong-1);
|
header2_offset = table2_body + 0x18*(target_subsong-1);
|
||||||
layers = read_16bit(header2_offset + 0x02,streamFile);
|
layers = read_16bit(header2_offset + 0x02,sf);
|
||||||
sample_rate = read_32bit(header2_offset + 0x04,streamFile);
|
sample_rate = read_32bit(header2_offset + 0x04,sf);
|
||||||
|
|
||||||
header3_offset = table3_body + 0x4c*(target_subsong-1);
|
header3_offset = table3_body + 0x4c*(target_subsong-1);
|
||||||
start_offset = read_32bit(header3_offset + 0x00,streamFile);
|
start_offset = read_32bit(header3_offset + 0x00,sf);
|
||||||
stream_size = read_32bit(header3_offset + 0x04,streamFile);
|
stream_size = read_32bit(header3_offset + 0x04,sf);
|
||||||
name_offset = header3_offset + 0x0c;
|
name_offset = header3_offset + 0x0c;
|
||||||
name_size = 0x40;
|
name_size = 0x40;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x58424F58: { /* "XBOX" */
|
case 0x58424F58: { /* "XBOX" */
|
||||||
size_t entry2_size = is_v1 || check_extensions(streamFile, "zsd") ? 0x14 : 0x1c;
|
size_t entry2_size = is_v1 || check_extensions(sf, "zsd") ? 0x14 : 0x1c;
|
||||||
|
|
||||||
/* BMX has unordered stream headers, and not every stream has a header */
|
/* BMX has unordered stream headers, and not every stream has a header */
|
||||||
header2_offset = 0;
|
header2_offset = 0;
|
||||||
for (i = 0; i < table2_entries; i++) {
|
for (i = 0; i < table2_entries; i++) {
|
||||||
int16_t id = read_16bit(table2_body + entry2_size*i + 0x00,streamFile);
|
int16_t id = read_16bit(table2_body + entry2_size*i + 0x00,sf);
|
||||||
|
|
||||||
if (id >= 0 && id + 1 != target_subsong) /* can be -1 == deleted entry */
|
if (id >= 0 && id + 1 != target_subsong) /* can be -1 == deleted entry */
|
||||||
continue;
|
continue;
|
||||||
@ -130,8 +130,8 @@ VGMSTREAM * init_vgmstream_zsnd(STREAMFILE *streamFile) {
|
|||||||
if (table2_entries > 0) {
|
if (table2_entries > 0) {
|
||||||
/* seems usable for sfx, meh */
|
/* seems usable for sfx, meh */
|
||||||
header2_offset = table2_body + entry2_size*0;
|
header2_offset = table2_body + entry2_size*0;
|
||||||
layers = read_16bit(header2_offset + 0x02,streamFile);
|
layers = read_16bit(header2_offset + 0x02,sf);
|
||||||
sample_rate = read_32bit(header2_offset + 0x04,streamFile);
|
sample_rate = read_32bit(header2_offset + 0x04,sf);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
layers = 0;
|
layers = 0;
|
||||||
@ -139,16 +139,16 @@ VGMSTREAM * init_vgmstream_zsnd(STREAMFILE *streamFile) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
layers = read_16bit(header2_offset + 0x02,streamFile);
|
layers = read_16bit(header2_offset + 0x02,sf);
|
||||||
sample_rate = read_32bit(header2_offset + 0x04,streamFile);
|
sample_rate = read_32bit(header2_offset + 0x04,sf);
|
||||||
if (entry2_size > 0x18) {
|
if (entry2_size > 0x18) {
|
||||||
layers2 = read_32bit(header2_offset + 0x18,streamFile);
|
layers2 = read_32bit(header2_offset + 0x18,sf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
header3_offset = table3_body + 0x54*(target_subsong-1);
|
header3_offset = table3_body + 0x54*(target_subsong-1);
|
||||||
start_offset = read_32bit(header3_offset + 0x00,streamFile);
|
start_offset = read_32bit(header3_offset + 0x00,sf);
|
||||||
stream_size = read_32bit(header3_offset + 0x04,streamFile);
|
stream_size = read_32bit(header3_offset + 0x04,sf);
|
||||||
/* 0x08: flags? related to looping? (not channels) */
|
/* 0x08: flags? related to looping? (not channels) */
|
||||||
//loop_end = read_32bit(header3_offset + 0x10,streamFile);
|
//loop_end = read_32bit(header3_offset + 0x10,streamFile);
|
||||||
name_offset = header3_offset + 0x14;
|
name_offset = header3_offset + 0x14;
|
||||||
@ -162,7 +162,7 @@ VGMSTREAM * init_vgmstream_zsnd(STREAMFILE *streamFile) {
|
|||||||
char filename[PATH_LIMIT];
|
char filename[PATH_LIMIT];
|
||||||
|
|
||||||
/* stream length isn't enough */
|
/* stream length isn't enough */
|
||||||
get_streamfile_filename(streamFile, filename, sizeof(filename));
|
get_streamfile_filename(sf, filename, sizeof(filename));
|
||||||
is_music = strcmp(filename, "music.zsd") == 0;
|
is_music = strcmp(filename, "music.zsd") == 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -183,15 +183,22 @@ VGMSTREAM * init_vgmstream_zsnd(STREAMFILE *streamFile) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case 0x50533220: /* "PS2 " (also for PSP) */
|
case 0x50533220: /* "PS2 " (also for PSP) */
|
||||||
if (table2_entries == 0) goto fail;
|
case 0x50535820: /* "PSX " */
|
||||||
|
if (table2_entries == 0) {
|
||||||
header2_offset = table2_body + 0x10*(target_subsong-1);
|
/* rare, seen in MUSIC.ZSD but SFX*.ZSD do have headers [Dave Mirra Freestyle BMX (PS1/PS2)] */
|
||||||
sample_rate = read_16bit(header2_offset + 0x02,streamFile);
|
sample_rate = 0x1000;
|
||||||
layers = read_16bit(header2_offset + 0x04,streamFile);
|
layers = 0x02;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
uint32_t header2_spacing = (is_v1) ? 0x0c : 0x10;
|
||||||
|
header2_offset = table2_body + header2_spacing * (target_subsong-1);
|
||||||
|
sample_rate = read_16bit(header2_offset + 0x02,sf);
|
||||||
|
layers = read_16bit(header2_offset + 0x04,sf);
|
||||||
|
}
|
||||||
|
|
||||||
header3_offset = table3_body + 0x08*(target_subsong-1);
|
header3_offset = table3_body + 0x08*(target_subsong-1);
|
||||||
start_offset = read_32bit(header3_offset + 0x00,streamFile);
|
start_offset = read_32bit(header3_offset + 0x00,sf);
|
||||||
stream_size = read_32bit(header3_offset + 0x04,streamFile);
|
stream_size = read_32bit(header3_offset + 0x04,sf);
|
||||||
name_offset = 0;
|
name_offset = 0;
|
||||||
name_size = 0;
|
name_size = 0;
|
||||||
|
|
||||||
@ -203,12 +210,12 @@ VGMSTREAM * init_vgmstream_zsnd(STREAMFILE *streamFile) {
|
|||||||
|
|
||||||
case 0x47435542: /* "GCUB" (also for Wii) */
|
case 0x47435542: /* "GCUB" (also for Wii) */
|
||||||
header2_offset = table2_body + 0x18*(target_subsong-1);
|
header2_offset = table2_body + 0x18*(target_subsong-1);
|
||||||
layers = read_16bit(header2_offset + 0x02,streamFile);
|
layers = read_16bit(header2_offset + 0x02,sf);
|
||||||
sample_rate = read_32bit(header2_offset + 0x04,streamFile);
|
sample_rate = read_32bit(header2_offset + 0x04,sf);
|
||||||
|
|
||||||
header3_offset = table3_body + 0x0c*(target_subsong-1);
|
header3_offset = table3_body + 0x0c*(target_subsong-1);
|
||||||
start_offset = read_32bit(header3_offset + 0x00,streamFile);
|
start_offset = read_32bit(header3_offset + 0x00,sf);
|
||||||
stream_size = read_32bit(header3_offset + 0x04,streamFile);
|
stream_size = read_32bit(header3_offset + 0x04,sf);
|
||||||
/* 0x08: "DSP " for some reason */
|
/* 0x08: "DSP " for some reason */
|
||||||
name_offset = 0;
|
name_offset = 0;
|
||||||
name_size = 0;
|
name_size = 0;
|
||||||
@ -220,17 +227,17 @@ VGMSTREAM * init_vgmstream_zsnd(STREAMFILE *streamFile) {
|
|||||||
|
|
||||||
/* maybe flags? */
|
/* maybe flags? */
|
||||||
switch (layers) {
|
switch (layers) {
|
||||||
case 0x00: channel_count = 1; break;
|
case 0x00: channels = 1; break;
|
||||||
case 0x01: channel_count = 1; break; /* set when looping? */
|
case 0x01: channels = 1; break; /* set when looping? */
|
||||||
case 0x02: channel_count = 2; break;
|
case 0x02: channels = 2; break;
|
||||||
case 0x22: channel_count = 4; break;
|
case 0x22: channels = 4; break;
|
||||||
default:
|
default:
|
||||||
VGM_LOG("ZSND: unknown layers\n");
|
VGM_LOG("ZSND: unknown flags %x\n", layers);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (layers2) {
|
if (layers2) {
|
||||||
channel_count = channel_count * layers2;
|
channels = channels * layers2;
|
||||||
}
|
}
|
||||||
|
|
||||||
loop_flag = 0;
|
loop_flag = 0;
|
||||||
@ -238,7 +245,7 @@ VGMSTREAM * init_vgmstream_zsnd(STREAMFILE *streamFile) {
|
|||||||
|
|
||||||
|
|
||||||
/* build the VGMSTREAM */
|
/* build the VGMSTREAM */
|
||||||
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
vgmstream = allocate_vgmstream(channels, loop_flag);
|
||||||
if (!vgmstream) goto fail;
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
vgmstream->meta_type = meta_ZSND;
|
vgmstream->meta_type = meta_ZSND;
|
||||||
@ -252,15 +259,15 @@ VGMSTREAM * init_vgmstream_zsnd(STREAMFILE *streamFile) {
|
|||||||
//vgmstream->layout_type = layout_interleave; /* interleaved stereo for >2ch*/
|
//vgmstream->layout_type = layout_interleave; /* interleaved stereo for >2ch*/
|
||||||
//vgmstream->interleave_block_size = 0x2000 * 2 / channel_count;
|
//vgmstream->interleave_block_size = 0x2000 * 2 / channel_count;
|
||||||
|
|
||||||
vgmstream->num_samples = ima_bytes_to_samples(stream_size, channel_count);
|
vgmstream->num_samples = ima_bytes_to_samples(stream_size, channels);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x58424F58: /* "XBOX" */
|
case 0x58424F58: /* "XBOX" */
|
||||||
vgmstream->coding_type = coding_XBOX_IMA;
|
vgmstream->coding_type = coding_XBOX_IMA;
|
||||||
vgmstream->layout_type = layout_interleave; /* interleaved stereo for >2ch*/
|
vgmstream->layout_type = layout_interleave; /* interleaved stereo for >2ch*/
|
||||||
vgmstream->interleave_block_size = 0x9000 * 2 / channel_count;
|
vgmstream->interleave_block_size = 0x9000 * 2 / channels;
|
||||||
|
|
||||||
vgmstream->num_samples = xbox_ima_bytes_to_samples(stream_size, channel_count);
|
vgmstream->num_samples = xbox_ima_bytes_to_samples(stream_size, channels);
|
||||||
|
|
||||||
/* very rarely entries refer to external .wma, but redoing the logic to handle only real
|
/* very rarely entries refer to external .wma, but redoing the logic to handle only real
|
||||||
* streams handle is a pain, so signal this case with an empty file [Aggresive Inline (Xbox)] */
|
* streams handle is a pain, so signal this case with an empty file [Aggresive Inline (Xbox)] */
|
||||||
@ -270,11 +277,12 @@ VGMSTREAM * init_vgmstream_zsnd(STREAMFILE *streamFile) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x50533220: /* "PS2 " (also for PSP) */
|
case 0x50533220: /* "PS2 " (also for PSP) */
|
||||||
|
case 0x50535820: /* "PSX " */
|
||||||
vgmstream->coding_type = coding_PSX;
|
vgmstream->coding_type = coding_PSX;
|
||||||
vgmstream->layout_type = layout_interleave;
|
vgmstream->layout_type = layout_interleave;
|
||||||
vgmstream->interleave_block_size = 0x800;
|
vgmstream->interleave_block_size = 0x800;
|
||||||
|
|
||||||
vgmstream->num_samples = ps_bytes_to_samples(stream_size, channel_count);
|
vgmstream->num_samples = ps_bytes_to_samples(stream_size, channels);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x47435542: /* "GCUB" (also for Wii) */
|
case 0x47435542: /* "GCUB" (also for Wii) */
|
||||||
@ -283,12 +291,12 @@ VGMSTREAM * init_vgmstream_zsnd(STREAMFILE *streamFile) {
|
|||||||
vgmstream->interleave_block_size = 0x8000;
|
vgmstream->interleave_block_size = 0x8000;
|
||||||
|
|
||||||
/* has a full DSP header, but num_samples may vary slighly between channels, so calc manually */
|
/* has a full DSP header, but num_samples may vary slighly between channels, so calc manually */
|
||||||
dsp_read_coefs_be(vgmstream, streamFile, start_offset+0x1c,0x60);
|
dsp_read_coefs_be(vgmstream, sf, start_offset+0x1c,0x60);
|
||||||
dsp_read_hist_be(vgmstream, streamFile, start_offset+0x40, 0x60);
|
dsp_read_hist_be(vgmstream, sf, start_offset+0x40, 0x60);
|
||||||
start_offset += 0x60*channel_count;
|
start_offset += 0x60*channels;
|
||||||
stream_size -= 0x60*channel_count;
|
stream_size -= 0x60*channels;
|
||||||
|
|
||||||
vgmstream->num_samples = dsp_bytes_to_samples(stream_size, channel_count);
|
vgmstream->num_samples = dsp_bytes_to_samples(stream_size, channels);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -299,20 +307,19 @@ VGMSTREAM * init_vgmstream_zsnd(STREAMFILE *streamFile) {
|
|||||||
vgmstream->stream_size = stream_size;
|
vgmstream->stream_size = stream_size;
|
||||||
|
|
||||||
if (name_offset) {
|
if (name_offset) {
|
||||||
read_string(vgmstream->stream_name,name_size, name_offset,streamFile);
|
read_string(vgmstream->stream_name,name_size, name_offset,sf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
temp_sf = setup_zsnd_streamfile(sf, start_offset, stream_size); /* fixes last interleave reads */
|
||||||
|
if (!temp_sf) goto fail;
|
||||||
|
|
||||||
temp_streamFile = setup_zsnd_streamfile(streamFile, start_offset, stream_size); /* fixes last interleave reads */
|
if (!vgmstream_open_stream(vgmstream,temp_sf,start_offset))
|
||||||
if (!temp_streamFile) goto fail;
|
|
||||||
|
|
||||||
if (!vgmstream_open_stream(vgmstream,temp_streamFile,start_offset))
|
|
||||||
goto fail;
|
goto fail;
|
||||||
close_streamfile(temp_streamFile);
|
close_streamfile(temp_sf);
|
||||||
return vgmstream;
|
return vgmstream;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
close_streamfile(temp_streamFile);
|
close_streamfile(temp_sf);
|
||||||
close_vgmstream(vgmstream);
|
close_vgmstream(vgmstream);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user