diff --git a/cli/vgmstream_cli.c b/cli/vgmstream_cli.c index 38d33d88..86092680 100644 --- a/cli/vgmstream_cli.c +++ b/cli/vgmstream_cli.c @@ -670,7 +670,8 @@ int main(int argc, char** argv) { return EXIT_SUCCESS; } - + if (cfg.seek_samples1 < -1) /* ex value for loop testing */ + cfg.seek_samples1 = vgmstream->loop_start_sample; if (cfg.seek_samples1 >= len_samples) cfg.seek_samples1 = -1; if (cfg.seek_samples2 >= len_samples) diff --git a/src/meta/imuse.c b/src/meta/imuse.c index 5b6222cc..a8706ebe 100644 --- a/src/meta/imuse.c +++ b/src/meta/imuse.c @@ -108,23 +108,19 @@ VGMSTREAM* init_vgmstream_imuse(STREAMFILE* sf) { if (!is_id4("DATA", head_offset + 0x10 + map_size + 0x00, sf)) goto fail; data_bytes = read_u32be(head_offset + 0x10 + map_size + 0x04, sf); - num_samples = data_bytes / channels / sizeof(int16_t); - //num_samples = (read_u32be(head_offset + 0x04,sf) - head_size) / channels / sizeof(int16_t); /* equivalent */ } else if (is_id4("RIFF", head_offset, sf)) { /* MCMP voices */ - /* standard (LE), with fake codec 1 and sizes also in decoded bytes (see above) */ + /* standard (LE), with fake codec 1 and sizes also in decoded bytes (see above), + * has standard RIFF chunks (may include extra), start offset in MCSC */ - if (!is_id4("fmt ", head_offset + 0x0c, sf)) + if (!find_chunk_le(sf, 0x666D7420, head_offset + 0x0c, 0, &offset, NULL)) /* "fmt " */ goto fail; - offset = head_offset + 0x14; channels = read_u16le(offset + 0x02,sf); sample_rate = read_u32le(offset + 0x04,sf); - if (!is_id4("data", head_offset + 0x24, sf)) + if (!find_chunk_le(sf, 0x64617461, head_offset + 0x0c, 0, NULL, &data_bytes)) /*"data"*/ goto fail; - data_bytes = read_u32le(head_offset + 0x28, sf); - num_samples = data_bytes / channels / sizeof(int16_t); } else { diff --git a/src/meta/msf.c b/src/meta/msf.c index 332dc643..dba75583 100644 --- a/src/meta/msf.c +++ b/src/meta/msf.c @@ -2,8 +2,8 @@ #include "../coding/coding.h" /* MSF - Sony's PS3 SDK format (MultiStream File) */ -VGMSTREAM * init_vgmstream_msf(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; +VGMSTREAM* init_vgmstream_msf(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; off_t start_offset; uint32_t data_size, loop_start = 0, loop_end = 0; uint32_t codec, flags; @@ -13,24 +13,24 @@ VGMSTREAM * init_vgmstream_msf(STREAMFILE *streamFile) { /* checks */ /* .msf: standard * .msa: Sonic & Sega All-Stars Racing (PS3) - * .at3: Silent Hill HD Collection (PS3) + * .at3: Silent Hill HD Collection (PS3), Z/X Zekkai no Crusade (PS3) * .mp3: Darkstalkers Resurrection (PS3) */ - if (!check_extensions(streamFile,"msf,msa,at3,mp3")) + if (!check_extensions(sf,"msf,msa,at3,mp3")) goto fail; /* check header "MSF" + version-char, usually: * 0x01, 0x02, 0x30 ("0"), 0x35 ("5"), 0x43 ("C") (last/most common version) */ - if ((read_32bitBE(0x00,streamFile) & 0xffffff00) != 0x4D534600) /* "MSF\0" */ + if ((read_u32be(0x00,sf) & 0xffffff00) != 0x4D534600) /* "MSF\0" */ goto fail; start_offset = 0x40; - codec = read_32bitBE(0x04,streamFile); - channel_count = read_32bitBE(0x08,streamFile); - data_size = read_32bitBE(0x0C,streamFile); /* without header */ + codec = read_u32be(0x04,sf); + channel_count = read_s32be(0x08,sf); + data_size = read_u32be(0x0C,sf); /* without header */ if (data_size == 0xFFFFFFFF) /* unneeded? */ - data_size = get_streamfile_size(streamFile) - start_offset; - sample_rate = read_32bitBE(0x10,streamFile); + data_size = get_streamfile_size(sf) - start_offset; + sample_rate = read_s32be(0x10,sf); /* byte flags, not in MSFv1 or v2 * 0x01/02/04/08: loop marker 0/1/2/3 @@ -38,15 +38,15 @@ VGMSTREAM * init_vgmstream_msf(STREAMFILE *streamFile) { * 0x20: VBR MP3 source (changed into simplified 0x1a1 CBR) * 0x40: joint stereo MP3 (apparently interleaved stereo for other formats) * 0x80+: (none/reserved) */ - flags = read_32bitBE(0x14,streamFile); + flags = read_u32be(0x14,sf); /* sometimes loop_start/end is set with flag 0x10, but from tests it only loops if 0x01/02 is set * 0x10 often goes with 0x01 but not always (Castlevania HoD); Malicious PS3 uses flag 0x2 instead */ loop_flag = flags != 0xffffffff && ((flags & 0x01) || (flags & 0x02)); /* loop markers (marker N @ 0x18 + N*(4+4), but in practice only marker 0 is used) */ if (loop_flag) { - loop_start = read_32bitBE(0x18,streamFile); - loop_end = read_32bitBE(0x1C,streamFile); /* loop duration */ + loop_start = read_u32be(0x18,sf); + loop_end = read_u32be(0x1C,sf); /* loop duration */ loop_end = loop_start + loop_end; /* usually equals data_size but not always */ if (loop_end > data_size)/* not seen */ loop_end = data_size; @@ -111,7 +111,7 @@ VGMSTREAM * init_vgmstream_msf(STREAMFILE *streamFile) { if (vgmstream->sample_rate == 0xFFFFFFFF) /* some MSFv1 (Digi World SP) */ vgmstream->sample_rate = 44100; /* voice tracks seems to use 44khz, not sure about other tracks */ - vgmstream->codec_data = init_ffmpeg_atrac3_raw(streamFile, start_offset,data_size, vgmstream->num_samples,vgmstream->channels,vgmstream->sample_rate, block_align, encoder_delay); + vgmstream->codec_data = init_ffmpeg_atrac3_raw(sf, start_offset,data_size, vgmstream->num_samples,vgmstream->channels,vgmstream->sample_rate, block_align, encoder_delay); if (!vgmstream->codec_data) goto fail; vgmstream->coding_type = coding_FFmpeg; vgmstream->layout_type = layout_none; @@ -129,7 +129,7 @@ VGMSTREAM * init_vgmstream_msf(STREAMFILE *streamFile) { #if defined(VGM_USE_MPEG) case 0x07: { /* MPEG (CBR LAME MP3) [Dengeki Bunko Fighting Climax (PS3)] */ - vgmstream->codec_data = init_mpeg(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels); + vgmstream->codec_data = init_mpeg(sf, start_offset, &vgmstream->coding_type, vgmstream->channels); if (!vgmstream->codec_data) goto fail; vgmstream->layout_type = layout_none; @@ -148,7 +148,7 @@ VGMSTREAM * init_vgmstream_msf(STREAMFILE *streamFile) { { /* MPEG (CBR LAME MP3) [Dengeki Bunko Fighting Climax (PS3)] */ ffmpeg_codec_data *ffmpeg_data = NULL; - ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset, streamFile->get_size(streamFile)); + ffmpeg_data = init_ffmpeg_offset(sf, start_offset, sf->get_size(sf)); if (!ffmpeg_data) goto fail; vgmstream->codec_data = ffmpeg_data; vgmstream->coding_type = coding_FFmpeg; @@ -171,7 +171,7 @@ VGMSTREAM * init_vgmstream_msf(STREAMFILE *streamFile) { } - if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + if (!vgmstream_open_stream(vgmstream,sf,start_offset)) goto fail; return vgmstream; diff --git a/src/meta/ps2_enth.c b/src/meta/ps2_enth.c index c3e6eb19..22a91f9d 100644 --- a/src/meta/ps2_enth.c +++ b/src/meta/ps2_enth.c @@ -1,94 +1,86 @@ #include "meta.h" -#include "../util.h" +#include "../coding/coding.h" -/* ENTH (from Enthusia - Professional Racing) */ -VGMSTREAM * init_vgmstream_ps2_enth(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; +/* LP/AP/LEP - from Enthusia: Professional Racing */ +VGMSTREAM* init_vgmstream_ps2_enth(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; off_t start_offset; - int header_check; - int loop_flag; - int channel_count; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("enth",filename_extension(filename))) goto fail; - - /* check header and loop_flag */ - header_check = read_32bitBE(0x00,streamFile); - switch (header_check) { - case 0x41502020: /* AP */ - loop_flag = (read_32bitLE(0x14,streamFile)!=0); - break; - case 0x4C455020: /* LEP */ - loop_flag = (read_32bitLE(0x58,streamFile)!=0); - break; - default: - goto fail; - } - - channel_count = 2; - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - header_check = read_32bitBE(0x00,streamFile); - - switch (header_check) { - case 0x41502020: /* AP */ - start_offset = read_32bitLE(0x1C,streamFile); - vgmstream->channels = channel_count; - vgmstream->sample_rate = read_32bitLE(0x08,streamFile); - vgmstream->coding_type = coding_PSX; - vgmstream->num_samples = (read_32bitLE(0x18,streamFile))*28/16/channel_count; - if (loop_flag) { - vgmstream->loop_start_sample = (read_32bitLE(0x14,streamFile))*28/16/channel_count; - vgmstream->loop_end_sample = (read_32bitLE(0x18,streamFile))*28/16/channel_count; - } - vgmstream->interleave_block_size = read_32bitLE(0x0C,streamFile); - break; - case 0x4C455020: /* LEP */ - start_offset = 0x800; - vgmstream->channels = channel_count; - vgmstream->sample_rate = (uint16_t)read_16bitLE(0x12,streamFile); - vgmstream->coding_type = coding_PSX; - vgmstream->num_samples = (read_32bitLE(0x08,streamFile))*28/16/channel_count; - if (loop_flag) { - vgmstream->loop_start_sample = (read_32bitLE(0x58,streamFile))*28/16/channel_count; - vgmstream->loop_end_sample = (read_32bitLE(0x08,streamFile))*28/16/channel_count; - } - vgmstream->interleave_block_size = 0x10; - break; - default: - goto fail; -} + int loop_flag, channels, sample_rate, interleave; + int32_t data_size, loop_start; + uint32_t id; - vgmstream->layout_type = layout_interleave; - vgmstream->meta_type = meta_PS2_ENTH; + /* checks */ + /* .bin/lbin: assumed (no actual extensino in bigfiles) + * .enth: fake */ + if (!check_extensions(sf, "bin,lbin,enth")) + 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;ich[i].streamfile = file; + id = read_32bitBE(0x00,sf); + switch (id) { + case 0x41502020: /* "AP " */ + case 0x4C502020: /* "LP " */ + sample_rate = read_u32le(0x08,sf); + interleave = read_u32le(0x0c,sf); + loop_start = read_u32le(0x14,sf); + data_size = read_u32le(0x18,sf); + start_offset = read_32bitLE(0x1C,sf); + break; - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset+ - vgmstream->interleave_block_size*i; + case 0x4C455020: /* "LEP " */ + data_size = read_u32le(0x08,sf); + sample_rate = read_u16le(0x12,sf); + loop_start = read_u32le(0x58,sf); + interleave = 0x10; + start_offset = 0x800; + break; - } + default: + goto fail; } - return vgmstream; + loop_flag = loop_start != 0; + channels = 2; - /* clean up anything we may have opened */ + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channels, loop_flag); + if (!vgmstream) goto fail; + + vgmstream->meta_type = meta_PS2_ENTH; + vgmstream->sample_rate = sample_rate; + + switch (id) { + case 0x4C502020: /* "LP " */ + vgmstream->coding_type = coding_PCM16LE; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = interleave; + + vgmstream->num_samples = pcm_bytes_to_samples(data_size, channels, 16); + vgmstream->loop_start_sample = pcm_bytes_to_samples(loop_start, channels, 16); + vgmstream->loop_end_sample = vgmstream->num_samples; + /* PCM data look different or encrypted + * some PCM16 must be xored(?) with 0x8000, not sure when */ + goto fail; + + case 0x41502020: /* "AP " */ + case 0x4C455020: /* "LEP " */ + vgmstream->coding_type = coding_PSX; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = interleave; + + vgmstream->num_samples = ps_bytes_to_samples(data_size, channels); + vgmstream->loop_start_sample = ps_bytes_to_samples(loop_start, channels); + vgmstream->loop_end_sample = vgmstream->num_samples; + break; + + default: + goto fail; + } + + if (!vgmstream_open_stream(vgmstream, sf, start_offset)) + goto fail; + return vgmstream; fail: - if (vgmstream) close_vgmstream(vgmstream); + close_vgmstream(vgmstream); return NULL; } diff --git a/src/vgmstream.c b/src/vgmstream.c index 9b27442f..ceda603c 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -167,7 +167,6 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = { init_vgmstream_seg, init_vgmstream_nds_strm_ffta2, init_vgmstream_str_asr, - init_vgmstream_zwdsp, init_vgmstream_gca, init_vgmstream_spt_spd, init_vgmstream_ish_isd, @@ -524,6 +523,7 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = { init_vgmstream_raw_pcm, /* .raw raw PCM */ init_vgmstream_s14_sss, /* .s14/sss raw siren14 */ init_vgmstream_raw_al, /* .al/al2 raw A-LAW */ + init_vgmstream_zwdsp, /* fake format */ #ifdef VGM_USE_FFMPEG init_vgmstream_ffmpeg, /* may play anything incorrectly, since FFmpeg doesn't check extensions */ #endif