From 6fc5e604e7e710c876d2fd09e3bc84f4fed65bd9 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 17 Oct 2020 19:00:02 +0200 Subject: [PATCH] Fix Enthusia PCM files and add .lp/ap/lep --- src/formats.c | 3 +++ src/libvgmstream.vcproj | 4 ++++ src/libvgmstream.vcxproj | 1 + src/libvgmstream.vcxproj.filters | 3 +++ src/meta/ps2_enth.c | 25 ++++++++++++-------- src/meta/ps2_enth_streamfile.h | 39 ++++++++++++++++++++++++++++++++ 6 files changed, 66 insertions(+), 9 deletions(-) create mode 100644 src/meta/ps2_enth_streamfile.h diff --git a/src/formats.c b/src/formats.c index 954691cd..041887dd 100644 --- a/src/formats.c +++ b/src/formats.c @@ -67,6 +67,7 @@ static const char* extension_list[] = { "ams", //txth/reserved [Super Dragon Ball Z (PS2) ELF names] "amts", //fake extension/header id for .stm (renamed? to be removed?) "ao", + "ap", "apc", "as4", "asd", @@ -261,6 +262,7 @@ static const char* extension_list[] = { "lasf", //fake extension for .asf (various) "lbin", //fake extension for .bin (various) "leg", + "lep", "lflac", //fake extension for .flac, FFmpeg/not parsed "lin", "lm0", @@ -277,6 +279,7 @@ static const char* extension_list[] = { "lmpc", //fake extension for .mpc, FFmpeg/not parsed "logg", //fake extension for .ogg "lopus", //fake extension for .opus + "lp", "lpcm", "lpk", "lps", diff --git a/src/libvgmstream.vcproj b/src/libvgmstream.vcproj index 8d593376..cb220ede 100644 --- a/src/libvgmstream.vcproj +++ b/src/libvgmstream.vcproj @@ -348,6 +348,10 @@ RelativePath=".\meta\ppst_streamfile.h" > + + diff --git a/src/libvgmstream.vcxproj b/src/libvgmstream.vcxproj index e96d3e40..c3853469 100644 --- a/src/libvgmstream.vcxproj +++ b/src/libvgmstream.vcxproj @@ -122,6 +122,7 @@ + diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters index 15167517..d26f3450 100644 --- a/src/libvgmstream.vcxproj.filters +++ b/src/libvgmstream.vcxproj.filters @@ -152,6 +152,9 @@ meta\Header Files + + meta\Header Files + meta\Header Files diff --git a/src/meta/ps2_enth.c b/src/meta/ps2_enth.c index 22a91f9d..bbe7dcf5 100644 --- a/src/meta/ps2_enth.c +++ b/src/meta/ps2_enth.c @@ -1,9 +1,11 @@ #include "meta.h" #include "../coding/coding.h" +#include "ps2_enth_streamfile.h" -/* LP/AP/LEP - from Enthusia: Professional Racing */ +/* LP/AP/LEP - from Konami (KCES)'s Enthusia: Professional Racing (PS2) */ VGMSTREAM* init_vgmstream_ps2_enth(STREAMFILE* sf) { VGMSTREAM* vgmstream = NULL; + STREAMFILE* temp_sf = NULL; off_t start_offset; int loop_flag, channels, sample_rate, interleave; int32_t data_size, loop_start; @@ -11,12 +13,13 @@ VGMSTREAM* init_vgmstream_ps2_enth(STREAMFILE* sf) { /* checks */ - /* .bin/lbin: assumed (no actual extensino in bigfiles) + /* .bin/lbin: internal (no names in bigfiles but exes mention "bgm%05d.bin" and "LEP data") + * .lp/lep/ap: header ID * .enth: fake */ - if (!check_extensions(sf, "bin,lbin,enth")) + if (!check_extensions(sf, "bin,lbin,lp,lep,ap,enth")) goto fail; - id = read_32bitBE(0x00,sf); + id = read_u32be(0x00,sf); switch (id) { case 0x41502020: /* "AP " */ case 0x4C502020: /* "LP " */ @@ -24,7 +27,7 @@ VGMSTREAM* init_vgmstream_ps2_enth(STREAMFILE* sf) { interleave = read_u32le(0x0c,sf); loop_start = read_u32le(0x14,sf); data_size = read_u32le(0x18,sf); - start_offset = read_32bitLE(0x1C,sf); + start_offset = read_u32le(0x1C,sf); break; case 0x4C455020: /* "LEP " */ @@ -42,6 +45,7 @@ VGMSTREAM* init_vgmstream_ps2_enth(STREAMFILE* sf) { loop_flag = loop_start != 0; channels = 2; + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channels, loop_flag); if (!vgmstream) goto fail; @@ -58,9 +62,10 @@ VGMSTREAM* init_vgmstream_ps2_enth(STREAMFILE* sf) { 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; + + temp_sf = setup_lp_streamfile(sf, start_offset); /* encrypted/obfuscated PCM */ + if (!temp_sf) goto fail; + break; case 0x41502020: /* "AP " */ case 0x4C455020: /* "LEP " */ @@ -77,10 +82,12 @@ VGMSTREAM* init_vgmstream_ps2_enth(STREAMFILE* sf) { goto fail; } - if (!vgmstream_open_stream(vgmstream, sf, start_offset)) + if (!vgmstream_open_stream(vgmstream, temp_sf ? temp_sf : sf, start_offset)) goto fail; + close_streamfile(temp_sf); return vgmstream; fail: + close_streamfile(temp_sf); close_vgmstream(vgmstream); return NULL; } diff --git a/src/meta/ps2_enth_streamfile.h b/src/meta/ps2_enth_streamfile.h new file mode 100644 index 00000000..5cac4131 --- /dev/null +++ b/src/meta/ps2_enth_streamfile.h @@ -0,0 +1,39 @@ +#ifndef _LP_STREAMFILE_H_ +#define _LP_STREAMFILE_H_ +#include "../streamfile.h" + + +typedef struct { + off_t start; +} lp_io_data; + +static size_t lp_io_read(STREAMFILE *sf, uint8_t *dest, off_t offset, size_t length, lp_io_data* data) { + int i; + size_t bytes = read_streamfile(dest, offset, length, sf); + + /* PCM16LE frames are ROL'ed (or lower bit is ignored?) so this only works if reads are aligned + * to sizeof(uint16_t); maybe could be a new decoder but seems like a waste */ + for (i = 0; i < bytes / 2 * 2; i += 2) { + if (offset + i >= data->start) { + uint16_t v = get_u16le(dest + i); + v = (v << 1) | ((v >> 15) & 0x0001); + put_u16le(dest + i, v); + } + } + + return bytes; +} + +/* decrypts Enthusia "LP" PCM streams */ +static STREAMFILE* setup_lp_streamfile(STREAMFILE* sf, off_t start) { + STREAMFILE* new_sf = NULL; + lp_io_data io_data = {0}; + + io_data.start = start; + + new_sf = open_wrap_streamfile(sf); + new_sf = open_io_streamfile_f(new_sf, &io_data, sizeof(lp_io_data), lp_io_read, NULL); + return new_sf; +} + +#endif /* _LP_STREAMFILE_H_ */