Merge pull request #1512 from bnnm/ssm-etc

- Fix .ssm subsongs [Kururin Squash! (GC)]
- Improve slightly FSB key testing performance
- Add DPCM_KCEJ TXTH codec [Metal Gear Solid 2 (PS2)]
- cleanup
This commit is contained in:
bnnm 2024-04-09 00:29:04 +02:00 committed by GitHub
commit f16b17355e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 360 additions and 158 deletions

View File

@ -161,9 +161,9 @@ different internally (encrypted, different versions, etc) and not always can be
- *ads_container*: `.ads .cads` - *ads_container*: `.ads .cads`
- Subfiles: *ads* - Subfiles: *ads*
- Codecs: PCM16LE DVI_IMA_int PSX - Codecs: PCM16LE DVI_IMA_int PSX
- **nps.c** - **npsf.c**
- Namco NPSF header [*NPS*] - Namco NPSF header [*NPS*]
- *nps*: `.nps .npsf` - *npsf*: `.nps .npsf`
- Codecs: PSX - Codecs: PSX
- **xa.c** - **xa.c**
- Sony XA header [*XA*] - Sony XA header [*XA*]
@ -200,7 +200,7 @@ different internally (encrypted, different versions, etc) and not always can be
- Electronic Arts BNK header [*EA_BNK*] - Electronic Arts BNK header [*EA_BNK*]
- Electronic Arts SCHl header [*EA_SCHL*] - Electronic Arts SCHl header [*EA_SCHL*]
- *ea_schl*: `.asf .lasf .str .chk .eam .exa .sng .aud .sx .xa .strm .stm .hab .xsf .gsf .(extensionless)` - *ea_schl*: `.asf .lasf .str .chk .eam .exa .sng .aud .sx .xa .strm .stm .hab .xsf .gsf .(extensionless)`
- *ea_schl_video*: `.uv .dct .mad .wve .vp6` - *ea_schl_video*: `.uv .dct .mad .wve .vp6 .mpc .lmpc`
- *ea_bnk*: `.bnk .sdt .hdt .ldt .abk .ast .cat` - *ea_bnk*: `.bnk .sdt .hdt .ldt .abk .ast .cat`
- *ea_abk*: `.abk + .ast` - *ea_abk*: `.abk + .ast`
- *ea_hdr_dat*: `.hdr + .dat` - *ea_hdr_dat*: `.hdr + .dat`
@ -241,7 +241,7 @@ different internally (encrypted, different versions, etc) and not always can be
- **aifc.c** - **aifc.c**
- Apple AIFF-C header [*AIFC*] - Apple AIFF-C header [*AIFC*]
- Apple AIFF header [*AIFF*] - Apple AIFF header [*AIFF*]
- *aifc*: `.aif .laif .wav .lwav .(extensionless) .aifc .laifc .afc .cbd2 .bgm .fda .n64 .xa .caf .aiff .laiff .acm .adp .ai .pcm` - *aifc*: `.aif .laif .wav .lwav .aiff .laiff .(extensionless) .aifc .laifc .afc .cbd2 .bgm .fda .n64 .xa .caf .acm .adp .ai .pcm`
- Codecs: SDX2 CBD2 DVI_IMA_int APPLE_IMA4 RELIC VADPCM PCM8 PCM16BE XA - Codecs: SDX2 CBD2 DVI_IMA_int APPLE_IMA4 RELIC VADPCM PCM8 PCM16BE XA
- **str_snds.c** - **str_snds.c**
- 3DO SNDS header [*STR_SNDS*] - 3DO SNDS header [*STR_SNDS*]
@ -271,7 +271,7 @@ different internally (encrypted, different versions, etc) and not always can be
- RIFF WAVE header (ctrl looping) [*RIFF_WAVE_MWV*] - RIFF WAVE header (ctrl looping) [*RIFF_WAVE_MWV*]
- RIFX WAVE header [*RIFX_WAVE*] - RIFX WAVE header [*RIFX_WAVE*]
- RIFX WAVE header (smpl looping) [*RIFX_WAVE_smpl*] - RIFX WAVE header (smpl looping) [*RIFX_WAVE_smpl*]
- *riff*: `.wav .lwav .xwav .mwv .da .dax .cd .med .snd .adx .adp .xss .xsew .adpcm .adw .wd .(extensionless) .sbv .wvx .str .at3 .rws .aud .at9 .ckd .saf .ima .nsa .pcm .xvag .ogg .logg .p1d .xms .mus .dat .ldat .wma .lwma .caf` - *riff*: `.wav .lwav .xwav .mwv .da .dax .cd .med .snd .adx .adp .xss .xsew .adpcm .adw .wd .(extensionless) .sbv .wvx .str .at3 .rws .aud .at9 .ckd .saf .ima .nsa .pcm .xvag .ogg .logg .p1d .xms .mus .dat .ldat .wma .lwma .caf .wax`
- *rifx*: `.wav .lwav` - *rifx*: `.wav .lwav`
- Codecs: AICA_int PCM32LE PCM24LE PCM16BE PCM16LE PCM8_U MSADPCM IMA PCMFLOAT MS_IMA AICA MPEG_custom XBOX_IMA MS_IMA_3BIT DVI_IMA L5_555 OGG_VORBIS ATRAC9 ATRAC3 MPEG MSADPCM_int - Codecs: AICA_int PCM32LE PCM24LE PCM16BE PCM16LE PCM8_U MSADPCM IMA PCMFLOAT MS_IMA AICA MPEG_custom XBOX_IMA MS_IMA_3BIT DVI_IMA L5_555 OGG_VORBIS ATRAC9 ATRAC3 MPEG MSADPCM_int
- **nwa.c** - **nwa.c**
@ -402,12 +402,6 @@ different internally (encrypted, different versions, etc) and not always can be
- *ps2_rkv*: `.rkv` - *ps2_rkv*: `.rkv`
- *ngc_rkv*: `.(extensionless) .rkv .bo2` - *ngc_rkv*: `.(extensionless) .rkv .bo2`
- Codecs: PSX NGC_DSP - Codecs: PSX NGC_DSP
- **ps2_vas.c**
- Konami .VAS header [*PS2_VAS*]
- *ps2_vas*: `.vas`
- *ps2_vas_container*: `.vas`
- Subfiles: *ps2_vas*
- Codecs: PSX
- **lp_ap_lep.c** - **lp_ap_lep.c**
- Konami LP/AP/LEP header [*LP_AP_LEP*] - Konami LP/AP/LEP header [*LP_AP_LEP*]
- *lp_ap_lep*: `.bin .lbin .lp .lep .ap` - *lp_ap_lep*: `.bin .lbin .lp .lep .ap`
@ -559,8 +553,8 @@ different internally (encrypted, different versions, etc) and not always can be
- *ydsp*: `.ydsp` - *ydsp*: `.ydsp`
- Codecs: NGC_DSP - Codecs: NGC_DSP
- **ngc_ssm.c** - **ngc_ssm.c**
- SSM DSP Header [*NGC_SSM*] - HAL Laboratory .SSM Header [*SSM*]
- *ngc_ssm*: `.ssm` - *ssm*: `.ssm`
- Codecs: NGC_DSP - Codecs: NGC_DSP
- **ps2_joe.c** - **ps2_joe.c**
- Asobo Studio .JOE header [*PS2_JOE*] - Asobo Studio .JOE header [*PS2_JOE*]
@ -1274,7 +1268,7 @@ different internally (encrypted, different versions, etc) and not always can be
- **h4m.c** - **h4m.c**
- Hudson HVQM4 header [*H4M*] - Hudson HVQM4 header [*H4M*]
- *h4m*: `.h4m .hvqm` - *h4m*: `.h4m .hvqm`
- Codecs: H4M_IMA - Codecs: H4M_IMA NGC_AFC
- **asf.c** - **asf.c**
- Argonaut ASF header [*ASF*] - Argonaut ASF header [*ASF*]
- *asf*: `.asf .lasf` - *asf*: `.asf .lasf`
@ -1674,7 +1668,7 @@ different internally (encrypted, different versions, etc) and not always can be
- **acx.c** - **acx.c**
- (container) - (container)
- *acx*: `.acx` - *acx*: `.acx`
- Subfiles: *adx* - Subfiles: *ogg_vorbis adx*
- **compresswave.c** - **compresswave.c**
- CompressWave .cwav header [*COMPRESSWAVE*] - CompressWave .cwav header [*COMPRESSWAVE*]
- *compresswave*: `.cwav` - *compresswave*: `.cwav`
@ -1816,14 +1810,24 @@ different internally (encrypted, different versions, etc) and not always can be
- Traveller's Tales CBX header [*CBX*] - Traveller's Tales CBX header [*CBX*]
- *cbx*: `.cbx` - *cbx*: `.cbx`
- Codecs: EA_MT - Codecs: EA_MT
- **scd_pcm.c** - **vas_rockstar.c**
- Lunar: Eternal Blue .PCM header [*SCD_PCM*] - Rockstar .VAS header [*VAS_ROCKSTAR*]
- *scd_pcm*: `.pcm` - *vas_rockstar*: `.vas`
- Codecs: PCM8_SB - Codecs: PSX
- **agsc.c** - **agsc.c**
- Retro Studios AGSC header [*AGSC*] - Retro Studios AGSC header [*AGSC*]
- *agsc*: `.agsc` - *agsc*: `.agsc`
- Codecs: NGC_DSP - Codecs: NGC_DSP
- **scd_pcm.c**
- Lunar: Eternal Blue .PCM header [*SCD_PCM*]
- *scd_pcm*: `.pcm`
- Codecs: PCM8_SB
- **vas_kceo.c**
- Konami .VAS header [*VAS_KCEO*]
- *vas_kceo*: `.vas`
- *vas_kceo_container*: `.vas`
- Subfiles: *vas_kceo*
- Codecs: PSX
- **ps2_wmus.c** - **ps2_wmus.c**
- assumed The Warriors Sony ADPCM by .wmus extension [*PS2_WMUS*] - assumed The Warriors Sony ADPCM by .wmus extension [*PS2_WMUS*]
- *ps2_wmus*: `.wmus` - *ps2_wmus*: `.wmus`

View File

@ -111,6 +111,8 @@ as explained below, but often will use default values. Accepted codec strings:
# - ALAW A-Law 8-bit PCM # - ALAW A-Law 8-bit PCM
# * For few rare games [Illwinter Game Design games: Conquest of Elysium 3 (PC), Dominions 3/4 (PC)] # * For few rare games [Illwinter Game Design games: Conquest of Elysium 3 (PC), Dominions 3/4 (PC)]
# * Interleave is multiple of 0x1 (default) # * Interleave is multiple of 0x1 (default)
# - DPCM_KCEJ DPCM 8-bit (KCE Japan)
# * For rare games [Metal Gear Solid 2 (PS2)-cutscenes]
# #
# - IMA IMA ADPCM (mono/stereo) # - IMA IMA ADPCM (mono/stereo)
# * For some PC games, and rarely consoles # * For some PC games, and rarely consoles

View File

@ -387,6 +387,7 @@ int decode_get_samples_per_frame(VGMSTREAM* vgmstream) {
case coding_ACM: case coding_ACM:
case coding_DERF: case coding_DERF:
case coding_WADY: case coding_WADY:
case coding_DPCM_KCEJ:
case coding_NWA: case coding_NWA:
case coding_SASSC: case coding_SASSC:
case coding_CIRCUS_ADPCM: case coding_CIRCUS_ADPCM:
@ -608,6 +609,7 @@ int decode_get_frame_size(VGMSTREAM* vgmstream) {
case coding_CBD2_int: case coding_CBD2_int:
case coding_DERF: case coding_DERF:
case coding_WADY: case coding_WADY:
case coding_DPCM_KCEJ:
case coding_NWA: case coding_NWA:
case coding_SASSC: case coding_SASSC:
case coding_CIRCUS_ADPCM: case coding_CIRCUS_ADPCM:
@ -1137,6 +1139,12 @@ void decode_vgmstream(VGMSTREAM* vgmstream, int samples_written, int samples_to_
vgmstream->channels, vgmstream->samples_into_block, samples_to_do); vgmstream->channels, vgmstream->samples_into_block, samples_to_do);
} }
break; break;
case coding_DPCM_KCEJ:
for (ch = 0; ch < vgmstream->channels; ch++) {
decode_dpcm_kcej(&vgmstream->ch[ch], buffer+ch,
vgmstream->channels, vgmstream->samples_into_block, samples_to_do);
}
break;
case coding_CIRCUS_ADPCM: case coding_CIRCUS_ADPCM:
for (ch = 0; ch < vgmstream->channels; ch++) { for (ch = 0; ch < vgmstream->channels; ch++) {
decode_circus_adpcm(&vgmstream->ch[ch], buffer+ch, decode_circus_adpcm(&vgmstream->ch[ch], buffer+ch,

View File

@ -248,6 +248,9 @@ void decode_derf(VGMSTREAMCHANNEL* stream, sample * outbuf, int channelspacing,
/* wady_decoder */ /* wady_decoder */
void decode_wady(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_wady(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
/* dpcm_kcej_decoder */
void decode_dpcm_kcej(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
/* circus_decoder */ /* circus_decoder */
typedef struct circus_codec_data circus_codec_data; typedef struct circus_codec_data circus_codec_data;

View File

@ -0,0 +1,44 @@
#include "coding.h"
static int expand_code(uint8_t code) {
int neg = code & 0x80;
int cmd = code & 0x07;
int v;
if (cmd == 7)
v = (code & 0x78) << 8;
else
v = ((code & 0x78) | 0x80) << 7;
v = (v >> cmd);
if (neg)
v = -v;
return v;
}
/* from the decompilation, mono mode seems to do this:
* hist_a += expand_code(codes[i++])
* hist_b += decode_byte(codes[i++])
* sample = (hist_a + hist_b) / 2;
* out[s++] = sample; //L
* out[s++] = sample; //R, repeated for to make fake stereo)
* Existing files seem to be all stereo though
*/
/* decompiled from the exe */
void decode_dpcm_kcej(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
off_t frame_offset = stream->offset; /* frame size is 1 */
int32_t hist = stream->adpcm_history1_32;
int sample_pos = 0;
for (int i = first_sample; i < first_sample + samples_to_do; i++) {
uint8_t code = read_u8(frame_offset + i, stream->streamfile);
hist += expand_code(code);
outbuf[sample_pos] = hist; /* no clamp */
sample_pos += channelspacing;
}
stream->adpcm_history1_32 = hist;
}

View File

@ -880,6 +880,7 @@ static const coding_info coding_info_list[] = {
{coding_SASSC, "Activision / EXAKT SASSC 8-bit DPCM"}, {coding_SASSC, "Activision / EXAKT SASSC 8-bit DPCM"},
{coding_DERF, "Xilam DERF 8-bit DPCM"}, {coding_DERF, "Xilam DERF 8-bit DPCM"},
{coding_WADY, "Marble WADY 8-bit DPCM"}, {coding_WADY, "Marble WADY 8-bit DPCM"},
{coding_DPCM_KCEJ, "Konami 8-bit DPCM"},
{coding_NWA, "VisualArt's NWA DPCM"}, {coding_NWA, "VisualArt's NWA DPCM"},
{coding_ACM, "InterPlay ACM"}, {coding_ACM, "InterPlay ACM"},
{coding_CIRCUS_ADPCM, "Circus 8-bit ADPCM"}, {coding_CIRCUS_ADPCM, "Circus 8-bit ADPCM"},
@ -1087,7 +1088,7 @@ static const meta_info meta_info_list[] = {
{meta_SCD_PCM, "Lunar: Eternal Blue .PCM header"}, {meta_SCD_PCM, "Lunar: Eternal Blue .PCM header"},
{meta_PS2_PCM, "Konami .PCM header"}, {meta_PS2_PCM, "Konami .PCM header"},
{meta_PS2_RKV, "Legacy of Kain - Blood Omen 2 RKV PS2 header"}, {meta_PS2_RKV, "Legacy of Kain - Blood Omen 2 RKV PS2 header"},
{meta_PS2_VAS, "Konami .VAS header"}, {meta_VAS_KCEO, "Konami .VAS header"},
{meta_LP_AP_LEP, "Konami LP/AP/LEP header"}, {meta_LP_AP_LEP, "Konami LP/AP/LEP header"},
{meta_SDT, "High Voltage .sdt header"}, {meta_SDT, "High Voltage .sdt header"},
{meta_WVS, "Swingin' Ape .WVS header"}, {meta_WVS, "Swingin' Ape .WVS header"},
@ -1125,7 +1126,7 @@ static const meta_info meta_info_list[] = {
{meta_ISH_ISD, "ISH+ISD DSP Header"}, {meta_ISH_ISD, "ISH+ISD DSP Header"},
{meta_GSND, "Tecmo GSND Header"}, {meta_GSND, "Tecmo GSND Header"},
{meta_YDSP, "Yuke's YDSP Header"}, {meta_YDSP, "Yuke's YDSP Header"},
{meta_NGC_SSM, "SSM DSP Header"}, {meta_SSM, "HAL Laboratory .SSM Header"},
{meta_PS2_JOE, "Asobo Studio .JOE header"}, {meta_PS2_JOE, "Asobo Studio .JOE header"},
{meta_VGS, "Guitar Hero VGS Header"}, {meta_VGS, "Guitar Hero VGS Header"},
{meta_DCS_WAV, "In Utero DCS+WAV header"}, {meta_DCS_WAV, "In Utero DCS+WAV header"},
@ -1431,7 +1432,7 @@ static const meta_info meta_info_list[] = {
{meta_NXOF, "Nihon Falcom FDK header"}, {meta_NXOF, "Nihon Falcom FDK header"},
{meta_GWB_GWD, "Ubisoft GWB+GWD header"}, {meta_GWB_GWD, "Ubisoft GWB+GWD header"},
{meta_CBX, "Traveller's Tales CBX header"}, {meta_CBX, "Traveller's Tales CBX header"},
{meta_VAS, "Manhunt 2 .VAS header"}, {meta_VAS_ROCKSTAR, "Rockstar .VAS header"},
}; };
void get_vgmstream_coding_description(VGMSTREAM* vgmstream, char* out, size_t out_size) { void get_vgmstream_coding_description(VGMSTREAM* vgmstream, char* out, size_t out_size) {

View File

@ -185,6 +185,7 @@
<ClInclude Include="util\layout_utils.h" /> <ClInclude Include="util\layout_utils.h" />
<ClInclude Include="util\log.h" /> <ClInclude Include="util\log.h" />
<ClInclude Include="util\m2_psb.h" /> <ClInclude Include="util\m2_psb.h" />
<ClInclude Include="util\meta_utils.h" />
<ClInclude Include="util\miniz.h" /> <ClInclude Include="util\miniz.h" />
<ClInclude Include="util\paths.h" /> <ClInclude Include="util\paths.h" />
<ClInclude Include="util\reader_get.h" /> <ClInclude Include="util\reader_get.h" />
@ -222,6 +223,7 @@
<ClCompile Include="coding\compresswave_decoder.c" /> <ClCompile Include="coding\compresswave_decoder.c" />
<ClCompile Include="coding\compresswave_decoder_lib.c" /> <ClCompile Include="coding\compresswave_decoder_lib.c" />
<ClCompile Include="coding\derf_decoder.c" /> <ClCompile Include="coding\derf_decoder.c" />
<ClCompile Include="coding\dpcm_kcej_decoder.c" />
<ClCompile Include="coding\dsa_decoder.c" /> <ClCompile Include="coding\dsa_decoder.c" />
<ClCompile Include="coding\ea_mt_decoder.c" /> <ClCompile Include="coding\ea_mt_decoder.c" />
<ClCompile Include="coding\ea_xas_decoder.c" /> <ClCompile Include="coding\ea_xas_decoder.c" />
@ -545,7 +547,7 @@
<ClCompile Include="meta\ngc_sck_dsp.c" /> <ClCompile Include="meta\ngc_sck_dsp.c" />
<ClCompile Include="meta\ngc_ssm.c" /> <ClCompile Include="meta\ngc_ssm.c" />
<ClCompile Include="meta\ngc_str_cauldron.c" /> <ClCompile Include="meta\ngc_str_cauldron.c" />
<ClCompile Include="meta\nps.c" /> <ClCompile Include="meta\npsf.c" />
<ClCompile Include="meta\nub.c" /> <ClCompile Include="meta\nub.c" />
<ClCompile Include="meta\nus3audio.c" /> <ClCompile Include="meta\nus3audio.c" />
<ClCompile Include="meta\nus3bank.c" /> <ClCompile Include="meta\nus3bank.c" />
@ -588,7 +590,6 @@
<ClCompile Include="meta\ps2_snd.c" /> <ClCompile Include="meta\ps2_snd.c" />
<ClCompile Include="meta\ps2_sps.c" /> <ClCompile Include="meta\ps2_sps.c" />
<ClCompile Include="meta\ps2_va3.c" /> <ClCompile Include="meta\ps2_va3.c" />
<ClCompile Include="meta\ps2_vas.c" />
<ClCompile Include="meta\ps2_vbk.c" /> <ClCompile Include="meta\ps2_vbk.c" />
<ClCompile Include="meta\ps2_vds_vdm.c" /> <ClCompile Include="meta\ps2_vds_vdm.c" />
<ClCompile Include="meta\ps2_vgv.c" /> <ClCompile Include="meta\ps2_vgv.c" />
@ -693,7 +694,8 @@
<ClCompile Include="meta\vab.c" /> <ClCompile Include="meta\vab.c" />
<ClCompile Include="meta\vag.c" /> <ClCompile Include="meta\vag.c" />
<ClCompile Include="meta\vai.c" /> <ClCompile Include="meta\vai.c" />
<ClCompile Include="meta\vas.c" /> <ClCompile Include="meta\vas_kceo.c" />
<ClCompile Include="meta\vas_rockstar.c" />
<ClCompile Include="meta\vgs.c" /> <ClCompile Include="meta\vgs.c" />
<ClCompile Include="meta\vgs_ps.c" /> <ClCompile Include="meta\vgs_ps.c" />
<ClCompile Include="meta\vid1.c" /> <ClCompile Include="meta\vid1.c" />
@ -765,6 +767,7 @@
<ClCompile Include="util\layout_utils.c" /> <ClCompile Include="util\layout_utils.c" />
<ClCompile Include="util\log.c" /> <ClCompile Include="util\log.c" />
<ClCompile Include="util\m2_psb.c" /> <ClCompile Include="util\m2_psb.c" />
<ClCompile Include="util\meta_utils.c" />
<ClCompile Include="util\miniz.c" /> <ClCompile Include="util\miniz.c" />
<ClCompile Include="util\paths.c" /> <ClCompile Include="util\paths.c" />
<ClCompile Include="util\reader.c" /> <ClCompile Include="util\reader.c" />

View File

@ -380,6 +380,9 @@
<ClInclude Include="util\m2_psb.h"> <ClInclude Include="util\m2_psb.h">
<Filter>util\Header Files</Filter> <Filter>util\Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="util\meta_utils.h">
<Filter>util\Header Files</Filter>
</ClInclude>
<ClInclude Include="util\miniz.h"> <ClInclude Include="util\miniz.h">
<Filter>util\Header Files</Filter> <Filter>util\Header Files</Filter>
</ClInclude> </ClInclude>
@ -487,6 +490,9 @@
<ClCompile Include="coding\derf_decoder.c"> <ClCompile Include="coding\derf_decoder.c">
<Filter>coding\Source Files</Filter> <Filter>coding\Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="coding\dpcm_kcej_decoder.c">
<Filter>coding\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\dsa_decoder.c"> <ClCompile Include="coding\dsa_decoder.c">
<Filter>coding\Source Files</Filter> <Filter>coding\Source Files</Filter>
</ClCompile> </ClCompile>
@ -1456,7 +1462,7 @@
<ClCompile Include="meta\ngc_str_cauldron.c"> <ClCompile Include="meta\ngc_str_cauldron.c">
<Filter>meta\Source Files</Filter> <Filter>meta\Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="meta\nps.c"> <ClCompile Include="meta\npsf.c">
<Filter>meta\Source Files</Filter> <Filter>meta\Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="meta\nub.c"> <ClCompile Include="meta\nub.c">
@ -1585,9 +1591,6 @@
<ClCompile Include="meta\ps2_va3.c"> <ClCompile Include="meta\ps2_va3.c">
<Filter>meta\Source Files</Filter> <Filter>meta\Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="meta\ps2_vas.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\ps2_vbk.c"> <ClCompile Include="meta\ps2_vbk.c">
<Filter>meta\Source Files</Filter> <Filter>meta\Source Files</Filter>
</ClCompile> </ClCompile>
@ -1900,7 +1903,10 @@
<ClCompile Include="meta\vai.c"> <ClCompile Include="meta\vai.c">
<Filter>meta\Source Files</Filter> <Filter>meta\Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="meta\vas.c"> <ClCompile Include="meta\vas_kceo.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\vas_rockstar.c">
<Filter>meta\Source Files</Filter> <Filter>meta\Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="meta\vgs.c"> <ClCompile Include="meta\vgs.c">
@ -2116,6 +2122,9 @@
<ClCompile Include="util\m2_psb.c"> <ClCompile Include="util\m2_psb.c">
<Filter>util\Source Files</Filter> <Filter>util\Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="util\meta_utils.c">
<Filter>util\Source Files</Filter>
</ClCompile>
<ClCompile Include="util\miniz.c"> <ClCompile Include="util\miniz.c">
<Filter>util\Source Files</Filter> <Filter>util\Source Files</Filter>
</ClCompile> </ClCompile>

View File

@ -65,8 +65,7 @@ static VGMSTREAM* test_fsbkey(STREAMFILE* sf, const uint8_t* key, size_t key_siz
int test_std = flags & FLAG_STD; int test_std = flags & FLAG_STD;
int test_alt = flags & FLAG_ALT; int test_alt = flags & FLAG_ALT;
if (!vc && test_std && test_fsb_streamfile(sf, key, key_size, 0)) {
if (!vc && test_std) {
temp_sf = setup_fsb_streamfile(sf, key, key_size, 0); temp_sf = setup_fsb_streamfile(sf, key, key_size, 0);
if (!temp_sf) return NULL; if (!temp_sf) return NULL;
//;dump_streamfile(temp_sf, 0); //;dump_streamfile(temp_sf, 0);
@ -77,7 +76,7 @@ static VGMSTREAM* test_fsbkey(STREAMFILE* sf, const uint8_t* key, size_t key_siz
close_streamfile(temp_sf); close_streamfile(temp_sf);
} }
if (!vc && test_alt) { if (!vc && test_alt && test_fsb_streamfile(sf, key, key_size, 1)) {
temp_sf = setup_fsb_streamfile(sf, key, key_size, 1); temp_sf = setup_fsb_streamfile(sf, key, key_size, 1);
if (!temp_sf) return NULL; if (!temp_sf) return NULL;
//;dump_streamfile(temp_sf, 1); //;dump_streamfile(temp_sf, 1);

View File

@ -71,4 +71,23 @@ static STREAMFILE* setup_fsb_streamfile(STREAMFILE* sf, const uint8_t* key, size
return new_sf; return new_sf;
} }
/* same as above but doesn't open streamfile, so it's a tiny bit faster */
static bool test_fsb_streamfile(STREAMFILE* sf, const uint8_t* key, size_t key_size, int is_alt) {
fsb_decryption_data io_data = {0};
if (!key_size || key_size >= FSB_KEY_MAX)
return false;
memcpy(io_data.key, key, key_size);
io_data.key_size = key_size;
io_data.is_alt = is_alt;
/* setup subfile */
uint8_t tmp[0x04];
int bytes = fsb_decryption_read(sf, tmp, 0x00, 0x04, &io_data);
if (bytes != 0x04)
return false;
return (get_u32be(tmp) & 0xFFFFFF00) == get_id32be("FSB\0");
}
#endif /* _FSB_ENCRYPTED_STREAMFILE_H_ */ #endif /* _FSB_ENCRYPTED_STREAMFILE_H_ */

View File

@ -76,6 +76,7 @@ static const fsbkey_info fsbkey_list[] = {
{ MODE_FSB4_ALT, FSBKEY_ADD("tkdnsem000") }, // Ys Online: The Call of Solum (PC) [FSB3] (alt key: 2ED62676CEA6B60C0C0C) { MODE_FSB4_ALT, FSBKEY_ADD("tkdnsem000") }, // Ys Online: The Call of Solum (PC) [FSB3] (alt key: 2ED62676CEA6B60C0C0C)
{ MODE_FSB4_STD, FSBKEY_ADD("4DxgpNV3pQLPD6GT7g9Gf6eWU7SXutGQ") }, // Test Drive: Ferrari Racing Legends (PC) { MODE_FSB4_STD, FSBKEY_ADD("4DxgpNV3pQLPD6GT7g9Gf6eWU7SXutGQ") }, // Test Drive: Ferrari Racing Legends (PC)
{ MODE_FSB4_STD, FSBKEY_ADD("AjaxIsTheGoodestBoy") }, // Hello Kitty: Island Adventure (iOS) { MODE_FSB4_STD, FSBKEY_ADD("AjaxIsTheGoodestBoy") }, // Hello Kitty: Island Adventure (iOS)
{ MODE_FSB5_STD, FSBKEY_ADD("resoforce") }, // Rivals of Aether 2 (PC)
/* these games use a key per file, generated from the filename; could be possible to add them but there is a lot of songs, /* these games use a key per file, generated from the filename; could be possible to add them but there is a lot of songs,
so external .fsbkey may be better (use guessfsb 3.1 with --write-key-file or ) */ so external .fsbkey may be better (use guessfsb 3.1 with --write-key-file or ) */

View File

@ -77,7 +77,7 @@ VGMSTREAM * init_vgmstream_rfrm(STREAMFILE *streamFile);
VGMSTREAM* init_vgmstream_ads(STREAMFILE* sf); VGMSTREAM* init_vgmstream_ads(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_ads_container(STREAMFILE* sf); VGMSTREAM* init_vgmstream_ads_container(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_nps(STREAMFILE *streamFile); VGMSTREAM* init_vgmstream_npsf(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_rs03(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_rs03(STREAMFILE *streamFile);
@ -248,8 +248,8 @@ VGMSTREAM * init_vgmstream_ps2_pcm(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ps2_rkv(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_ps2_rkv(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ps2_vas(STREAMFILE * streamFile); VGMSTREAM* init_vgmstream_vas_kceo(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_ps2_vas_container(STREAMFILE * streamFile); VGMSTREAM* init_vgmstream_vas_kceo_container(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_lp_ap_lep(STREAMFILE* sf); VGMSTREAM* init_vgmstream_lp_ap_lep(STREAMFILE* sf);
@ -330,7 +330,7 @@ VGMSTREAM * init_vgmstream_ydsp(STREAMFILE * streamFile);
VGMSTREAM* init_vgmstream_gsnd(STREAMFILE* sf); VGMSTREAM* init_vgmstream_gsnd(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_ngc_ssm(STREAMFILE * streamFile); VGMSTREAM* init_vgmstream_ssm(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_ps2_joe(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_ps2_joe(STREAMFILE * streamFile);
@ -1002,6 +1002,6 @@ VGMSTREAM* init_vgmstream_gwb_gwd(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_cbx(STREAMFILE* sf); VGMSTREAM* init_vgmstream_cbx(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_vas(STREAMFILE* sf); VGMSTREAM* init_vgmstream_vas_rockstar(STREAMFILE* sf);
#endif /*_META_H*/ #endif /*_META_H*/

View File

@ -1,96 +1,85 @@
#include "meta.h" #include "meta.h"
#include "../util.h" #include "../util/meta_utils.h"
#include "../coding/coding.h"
/* SSM (Golden Gashbell Full Power GC) */
VGMSTREAM * init_vgmstream_ngc_ssm(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t start_offset;
int loop_flag;
int channel_count;
int coef1_start;
int coef2_start;
int second_channel_start;
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("ssm",filename_extension(filename)))
goto fail;
/* check header */
#if 0
if (read_32bitBE(0x00,streamFile) != 0x0)
goto fail;
#endif
loop_flag = (uint32_t)read_16bitBE(0x18,streamFile);
channel_count = read_32bitBE(0x10,streamFile);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
start_offset = read_32bitBE(0x0,streamFile);
vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitBE(0x14,streamFile);
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->num_samples = read_32bitBE(0x04,streamFile)*14/8/channel_count;
if (loop_flag) {
vgmstream->loop_start_sample = read_32bitBE(0x24,streamFile)*14/8/channel_count;
vgmstream->loop_end_sample = read_32bitBE(0x20,streamFile)*14/8/channel_count;
}
vgmstream->layout_type = layout_none;
vgmstream->meta_type = meta_NGC_SSM;
/* Retrieveing the coef tables and the start of the second channel*/
coef1_start = 0x28;
coef2_start = 0x68;
second_channel_start = (read_32bitBE(0x04,streamFile)/2)+start_offset;
{
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);
}
}
/* open the file for reading */ /* .SSM - from Hal Laboratory games [Smash Bros Melee! (GC), Konjiki no Gashbell: YnTB Full Power (GC), Kururin Squash! (GC)] */
{ VGMSTREAM* init_vgmstream_ssm(STREAMFILE* sf) {
int i; meta_header_t h = {0};
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;
/* The first channel */
vgmstream->ch[0].channel_start_offset=
vgmstream->ch[0].offset=start_offset;
/* The second channel */ /* checks */
if (channel_count == 2) { h.head_size = read_u32be(0x00,sf);
vgmstream->ch[1].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); h.data_size = read_u32be(0x04,sf);
h.total_subsongs = read_s32be(0x08,sf);
int file_id = read_u32be(0x0c,sf);
if (!vgmstream->ch[1].streamfile) goto fail; /* extra tests + arbitrary maxes since no good header ID and values aren't exact */
if (0x10 + h.head_size + h.data_size > get_streamfile_size(sf))
return NULL;
if (h.head_size < h.total_subsongs * 0x48 || h.total_subsongs <= 0 || h.total_subsongs > 0x1000 || file_id > 0x1000)
return NULL;
if (!check_extensions(sf, "ssm"))
return NULL;
vgmstream->ch[1].channel_start_offset= h.target_subsong = sf->stream_index;
vgmstream->ch[1].offset=second_channel_start; if (!check_subsongs(&h.target_subsong, h.total_subsongs))
} return NULL;
}
/* sometimes there is padding after head_size, DSP's start ps matches this */
h.data_offset = get_streamfile_size(sf) - h.data_size; //0x10 + h.head_size;
uint32_t offset = 0x10;
for (int i = 0; i < h.total_subsongs; i++) {
int channels = read_u32be(offset + 0x00,sf);
if (channels < 1 || channels > 2) return NULL;
if (i + 1 == h.target_subsong) {
h.channels = read_u32be(offset + 0x00,sf);
h.sample_rate = read_s32be(offset + 0x04,sf);
/* use first channel as base */
h.loop_flag = read_s16be(offset + 0x08,sf);
h.loop_start = read_u32be(offset + 0x0c,sf);
h.chan_size = read_u32be(offset + 0x10,sf);
h.stream_offset = read_s32be(offset + 0x14,sf);
h.coefs_offset = offset + 0x18;
h.coefs_spacing = 0x40;
h.hists_offset = h.coefs_offset + 0x24;
h.hists_spacing = h.coefs_spacing;
if (h.channels >= 2) {
h.interleave = read_s32be(offset + 0x54,sf); /* use 2nd channel offset as interleave */
}
break;
}
offset += 0x08 + channels * 0x40;
} }
return vgmstream; /* oddly enough values are in absolute nibbles within the stream, adjust them here
* rarely may even point to a nibble after the header one (ex. 0x1005), but it's adjusted to 0x00 here */
h.loop_start -= h.stream_offset;
h.chan_size -= h.stream_offset;
if (h.interleave)
h.interleave -= h.stream_offset;
/* clean up anything we may have opened */ h.loop_start = dsp_nibbles_to_samples(h.loop_start);
fail: h.loop_end = dsp_nibbles_to_samples(h.chan_size);
if (vgmstream) close_vgmstream(vgmstream); h.num_samples = h.loop_end;
return NULL;
h.stream_offset = (h.stream_offset / 0x10 * 0x08) + h.data_offset;
h.stream_size = (h.chan_size / 0x10 * 0x08 + (h.chan_size % 0x08 ? 0x08 : 0x00)) * h.channels;
h.interleave = h.interleave / 0x10 * 0x08;
h.coding = coding_NGC_DSP;
h.layout = layout_interleave; //TODO layout flat + channel offset may be more appropriate
h.meta = meta_SSM;
h.sf = sf;
h.big_endian = true;
h.open_stream = true;
return alloc_metastream(&h);
} }

View File

@ -2,25 +2,25 @@
#include "../coding/coding.h" #include "../coding/coding.h"
/* NPFS - found in Namco NuSound v1 games [Tekken 5 (PS2), Venus & Braves (PS2), Ridge Racer (PSP)] */ /* NPFS - found in Namco NuSound v1 games [Tekken 5 (PS2), Venus & Braves (PS2), Ridge Racer (PSP)] */
VGMSTREAM* init_vgmstream_nps(STREAMFILE* sf) { VGMSTREAM* init_vgmstream_npsf(STREAMFILE* sf) {
VGMSTREAM * vgmstream = NULL; VGMSTREAM* vgmstream = NULL;
off_t start_offset; off_t start_offset;
uint32_t channel_size; uint32_t channel_size;
int loop_flag, channel_count, loop_start, sample_rate; int loop_flag, channels, loop_start, sample_rate;
/* checks */ /* checks */
if (!is_id32be(0x00, sf, "NPSF"))
return NULL;
/* .nps: referenced extension (ex. Venus & Braves, Ridge Racer data files) /* .nps: referenced extension (ex. Venus & Braves, Ridge Racer data files)
* .npsf: header id (Namco Production Sound File?) */ * .npsf: header id (Namco Production Sound File?) */
if ( !check_extensions(sf,"nps,npsf")) if (!check_extensions(sf,"nps,npsf"))
goto fail; return NULL;
if (read_u32be(0x00, sf) != 0x4E505346) /* "NPSF" */
goto fail;
/* 0x04: version? (0x00001000 = 1.00?) */ /* 0x04: version? (0x00001000 = 1.00?) */
channel_size = read_s32le(0x08, sf); channel_size = read_s32le(0x08, sf);
channel_count = read_s32le(0x0C, sf); channels = read_s32le(0x0C, sf);
start_offset = read_s32le(0x10, sf); /* interleave? */ start_offset = read_s32le(0x10, sf); /* interleave? */
loop_start = read_s32le(0x14, sf); loop_start = read_s32le(0x14, sf);
sample_rate = read_s32le(0x18, sf); sample_rate = read_s32le(0x18, sf);
@ -36,7 +36,7 @@ VGMSTREAM* init_vgmstream_nps(STREAMFILE* sf) {
/* 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->sample_rate = sample_rate; vgmstream->sample_rate = sample_rate;

View File

@ -56,6 +56,7 @@ typedef enum {
YMZ, YMZ,
ULAW, ULAW,
ALAW, ALAW,
DPCM_KCEJ,
UNKNOWN = 255, UNKNOWN = 255,
} txth_codec_t; } txth_codec_t;
@ -234,16 +235,16 @@ VGMSTREAM* init_vgmstream_txth(STREAMFILE* sf) {
case PSX_bf: case PSX_bf:
case HEVAG: interleave = 0x10; break; case HEVAG: interleave = 0x10; break;
case NGC_DSP: interleave = 0x08; break; case NGC_DSP: interleave = 0x08; break;
case PCM_FLOAT_LE: interleave = 0x04; break;
case PCM24LE: interleave = 0x03; break; case PCM24LE: interleave = 0x03; break;
case PCM24BE: interleave = 0x03; break; case PCM24BE: interleave = 0x03; break;
case PCM16LE: case PCM16LE:
case PCM16BE: interleave = 0x02; break; case PCM16BE: interleave = 0x02; break;
case PCM8: case PCM8:
case PCM8_U: case PCM8_U:
case PCM8_SB: interleave = 0x01; break; case PCM8_SB:
case PCM_FLOAT_LE: interleave = 0x04; break;
case ULAW: case ULAW:
case ALAW: interleave = 0x01; break; case ALAW:
default: default:
break; break;
} }
@ -267,6 +268,7 @@ VGMSTREAM* init_vgmstream_txth(STREAMFILE* sf) {
case PCM8_SB: coding = coding_PCM8_SB; break; case PCM8_SB: coding = coding_PCM8_SB; break;
case ULAW: coding = coding_ULAW; break; case ULAW: coding = coding_ULAW; break;
case ALAW: coding = coding_ALAW; break; case ALAW: coding = coding_ALAW; break;
case DPCM_KCEJ: coding = coding_DPCM_KCEJ; break;
case PCM_FLOAT_LE: coding = coding_PCMFLOAT; break; case PCM_FLOAT_LE: coding = coding_PCMFLOAT; break;
case SDX2: coding = coding_SDX2; break; case SDX2: coding = coding_SDX2; break;
case DVI_IMA: coding = coding_DVI_IMA; break; case DVI_IMA: coding = coding_DVI_IMA; break;
@ -417,6 +419,12 @@ VGMSTREAM* init_vgmstream_txth(STREAMFILE* sf) {
vgmstream->allow_dual_stereo = 1; /* known to be used in: PSX, AICA, YMZ */ vgmstream->allow_dual_stereo = 1; /* known to be used in: PSX, AICA, YMZ */
break; break;
case coding_DPCM_KCEJ:
if (vgmstream->channels == 1) goto fail; /* untested/unknown */
vgmstream->interleave_block_size = 0x01;
vgmstream->layout_type = layout_interleave;
break;
case coding_PCFX: case coding_PCFX:
vgmstream->interleave_block_size = txth.interleave; vgmstream->interleave_block_size = txth.interleave;
vgmstream->interleave_last_block_size = txth.interleave_last; vgmstream->interleave_last_block_size = txth.interleave_last;
@ -1011,6 +1019,7 @@ static txth_codec_t parse_codec(txth_header* txth, const char* val) {
else if (is_string(val,"HEVAG")) return HEVAG; else if (is_string(val,"HEVAG")) return HEVAG;
else if (is_string(val,"ULAW")) return ULAW; else if (is_string(val,"ULAW")) return ULAW;
else if (is_string(val,"ALAW")) return ALAW; else if (is_string(val,"ALAW")) return ALAW;
else if (is_string(val,"DPCM_KCEJ")) return DPCM_KCEJ;
/* special handling */ /* special handling */
else if (is_string(val,"name_value")) return txth->name_values[0]; else if (is_string(val,"name_value")) return txth->name_values[0];
else if (is_string(val,"name_value1")) return txth->name_values[0]; else if (is_string(val,"name_value1")) return txth->name_values[0];
@ -2157,6 +2166,7 @@ static int get_bytes_to_samples(txth_header* txth, uint32_t bytes) {
case PCM8_SB: case PCM8_SB:
case ULAW: case ULAW:
case ALAW: case ALAW:
case DPCM_KCEJ:
return pcm8_bytes_to_samples(bytes, txth->channels); return pcm8_bytes_to_samples(bytes, txth->channels);
case PCM_FLOAT_LE: case PCM_FLOAT_LE:
return pcm_bytes_to_samples(bytes, txth->channels, 32); return pcm_bytes_to_samples(bytes, txth->channels, 32);

View File

@ -2,8 +2,8 @@
#include "../coding/coding.h" #include "../coding/coding.h"
/* .VAS - from Konami Jikkyou Powerful Pro Yakyuu games */ /* .VAS - from Konami Computer Enterntainment Osaka games [Jikkyou Powerful Pro Yakyuu 8 (PS2), Jikkyou World Soccer 2000 (PS2)] */
VGMSTREAM* init_vgmstream_ps2_vas(STREAMFILE* sf) { VGMSTREAM* init_vgmstream_vas_kceo(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL; VGMSTREAM* vgmstream = NULL;
off_t start_offset; off_t start_offset;
int loop_flag, channels; int loop_flag, channels;
@ -11,9 +11,9 @@ VGMSTREAM* init_vgmstream_ps2_vas(STREAMFILE* sf) {
/* checks */ /* checks */
if (!check_extensions(sf, "vas")) if (!check_extensions(sf, "vas"))
goto fail; return NULL;
if (read_u32le(0x00,sf) + 0x800 != get_streamfile_size(sf)) if (read_u32le(0x00,sf) + 0x800 != get_streamfile_size(sf))
goto fail; return NULL;
loop_flag = (read_u32le(0x10,sf) != 0); loop_flag = (read_u32le(0x10,sf) != 0);
channels = 2; channels = 2;
@ -25,10 +25,10 @@ VGMSTREAM* init_vgmstream_ps2_vas(STREAMFILE* sf) {
/* build the VGMSTREAM */ /* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels,loop_flag); vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail; if (!vgmstream) goto fail;
vgmstream->meta_type = meta_PS2_VAS; vgmstream->meta_type = meta_VAS_KCEO;
vgmstream->sample_rate = read_s32le(0x04,sf); vgmstream->sample_rate = read_s32le(0x04,sf);
vgmstream->coding_type = coding_PSX; vgmstream->coding_type = coding_PSX;
@ -50,7 +50,7 @@ fail:
/* .VAS in containers */ /* .VAS in containers */
VGMSTREAM* init_vgmstream_ps2_vas_container(STREAMFILE* sf) { VGMSTREAM* init_vgmstream_vas_kceo_container(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL; VGMSTREAM* vgmstream = NULL;
STREAMFILE* temp_sf = NULL; STREAMFILE* temp_sf = NULL;
off_t subfile_offset = 0; off_t subfile_offset = 0;
@ -60,7 +60,7 @@ VGMSTREAM* init_vgmstream_ps2_vas_container(STREAMFILE* sf) {
/* checks */ /* checks */
if (!check_extensions(sf, "vas")) if (!check_extensions(sf, "vas"))
goto fail; return NULL;
if (read_u32be(0x00, sf) == 0xAB8A5A00) { /* fixed value */ if (read_u32be(0x00, sf) == 0xAB8A5A00) { /* fixed value */
@ -139,7 +139,7 @@ VGMSTREAM* init_vgmstream_ps2_vas_container(STREAMFILE* sf) {
temp_sf = setup_subfile_streamfile(sf, subfile_offset,subfile_size, NULL); temp_sf = setup_subfile_streamfile(sf, subfile_offset,subfile_size, NULL);
if (!temp_sf) goto fail; if (!temp_sf) goto fail;
vgmstream = init_vgmstream_ps2_vas(temp_sf); vgmstream = init_vgmstream_vas_kceo(temp_sf);
if (!vgmstream) goto fail; if (!vgmstream) goto fail;
vgmstream->num_streams = total_subsongs; vgmstream->num_streams = total_subsongs;

View File

@ -2,7 +2,7 @@
#include "../coding/coding.h" #include "../coding/coding.h"
/* VAS - Manhunt 2 [PSP] blocked audio format */ /* VAS - Manhunt 2 [PSP] blocked audio format */
VGMSTREAM* init_vgmstream_vas(STREAMFILE* sf) { VGMSTREAM* init_vgmstream_vas_rockstar(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL; VGMSTREAM* vgmstream = NULL;
off_t stream_offset; off_t stream_offset;
size_t data_size, stream_size, block_size = 0x40; size_t data_size, stream_size, block_size = 0x40;
@ -14,10 +14,10 @@ VGMSTREAM* init_vgmstream_vas(STREAMFILE* sf) {
/* VAGs: v1, used in prerelease builds /* VAGs: v1, used in prerelease builds
* 2AGs: v2, used in the final release */ * 2AGs: v2, used in the final release */
if (!is_id32be(0x00, sf, "VAGs") && !is_id32be(0x00, sf, "2AGs")) if (!is_id32be(0x00, sf, "VAGs") && !is_id32be(0x00, sf, "2AGs"))
goto fail; return NULL;
if (!check_extensions(sf, "vas")) if (!check_extensions(sf, "vas"))
goto fail; return NULL;
/* parse header */ /* parse header */
@ -26,7 +26,7 @@ VGMSTREAM* init_vgmstream_vas(STREAMFILE* sf) {
if (read_u8(0x0A, sf)) goto fail; /* always 0? */ if (read_u8(0x0A, sf)) goto fail; /* always 0? */
num_streams = read_u8(0x0B, sf); num_streams = read_u8(0x0B, sf);
if (num_streams < 1 || num_streams > 32) goto fail; if (target_subsong < 0 || num_streams < 1 || num_streams > 32) goto fail;
if (!target_subsong) target_subsong = 1; if (!target_subsong) target_subsong = 1;
channels = 1; /* might be read_u8(0x0A, sf) + 1? */ channels = 1; /* might be read_u8(0x0A, sf) + 1? */
@ -56,7 +56,7 @@ VGMSTREAM* init_vgmstream_vas(STREAMFILE* sf) {
vgmstream = allocate_vgmstream(channels, loop_flag); vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail; if (!vgmstream) goto fail;
vgmstream->meta_type = meta_VAS; vgmstream->meta_type = meta_VAS_ROCKSTAR;
vgmstream->coding_type = coding_PSX; vgmstream->coding_type = coding_PSX;
vgmstream->num_streams = num_streams; vgmstream->num_streams = num_streams;
vgmstream->sample_rate = sample_rate; vgmstream->sample_rate = sample_rate;

48
src/util/meta_utils.c Normal file
View File

@ -0,0 +1,48 @@
#include "../vgmstream.h"
#include "meta_utils.h"
/* Allocate memory and setup a VGMSTREAM */
VGMSTREAM* alloc_metastream(meta_header_t* h) {
if (h->sample_rate <= 0 || h->sample_rate > VGMSTREAM_MAX_SAMPLE_RATE)
return NULL;
if (h->num_samples <= 0 || h->num_samples > VGMSTREAM_MAX_NUM_SAMPLES)
return NULL;
VGMSTREAM* vgmstream = allocate_vgmstream(h->channels, h->loop_flag);
if (!vgmstream) return NULL;
//vgmstream->channels = h->channels;
vgmstream->sample_rate = h->sample_rate;
vgmstream->num_samples = h->num_samples;
vgmstream->loop_start_sample = h->loop_start;
vgmstream->loop_end_sample = h->loop_end;
vgmstream->coding_type = h->coding;
vgmstream->layout_type = h->layout;
vgmstream->meta_type = h->meta;
vgmstream->num_streams = h->total_subsongs;
vgmstream->stream_size = h->stream_size;
vgmstream->interleave_block_size = h->interleave;
if (h->coding == coding_NGC_DSP && (h->sf || h->sf_head)) {
if (h->coefs_offset || h->coefs_spacing)
dsp_read_coefs(vgmstream, h->sf ? h->sf : h->sf_head, h->coefs_offset, h->coefs_spacing, h->big_endian);
if (h->hists_offset || h->hists_spacing)
dsp_read_hist (vgmstream, h->sf ? h->sf : h->sf_head, h->hists_offset, h->hists_spacing, h->big_endian);
}
if (h->open_stream) {
if (!vgmstream_open_stream(vgmstream, h->sf ? h->sf : h->sf_head, h->stream_offset))
goto fail;
}
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

61
src/util/meta_utils.h Normal file
View File

@ -0,0 +1,61 @@
#ifndef _META_UTILS_H
#define _META_UTILS_H
#include "../streamtypes.h"
#include "reader_get.h"
#include "reader_put.h"
#include "../coding/coding.h"
/* Helper struct for common numbers (no need to use all), to use with helper functions.
* Preferably declare after validating header ID as it's faster (by a minuscule amount). */
typedef struct {
/* should be set */
int channels;
int sample_rate;
int32_t num_samples;
/* optional info */
bool loop_flag;
int32_t loop_start;
int32_t loop_end;
int target_subsong;
int total_subsongs;
int32_t interleave;
/* common helpers */
uint32_t stream_offset; /* where current stream starts */
uint32_t stream_size; /* current stream size */
uint32_t data_offset; /* where data (first stream) starts */
uint32_t data_size; /* data for all streams */
uint32_t head_size; /* size of some header part */
uint32_t chan_offset;
uint32_t chan_size;
uint32_t coefs_offset;
uint32_t coefs_spacing;
uint32_t hists_offset;
uint32_t hists_spacing;
/* optional but can be used for some actions */
bool big_endian;
coding_t coding;
layout_t layout;
meta_t meta;
/* only sf_head is used to read coefs and such */
STREAMFILE* sf;
STREAMFILE* sf_head;
STREAMFILE* sf_body;
bool open_stream;
} meta_header_t;
VGMSTREAM* alloc_metastream(meta_header_t* h);
/* checks max subsongs and setups target */
//bool check_subsongs(int* target_subsong, int total_subsongs);
#endif

View File

@ -39,7 +39,7 @@ init_vgmstream_t init_vgmstream_functions[] = {
init_vgmstream_cstr, init_vgmstream_cstr,
init_vgmstream_gcsw, init_vgmstream_gcsw,
init_vgmstream_ads, init_vgmstream_ads,
init_vgmstream_nps, init_vgmstream_npsf,
init_vgmstream_xa, init_vgmstream_xa,
init_vgmstream_rxws, init_vgmstream_rxws,
init_vgmstream_ngc_dsp_stm, init_vgmstream_ngc_dsp_stm,
@ -98,8 +98,6 @@ init_vgmstream_t init_vgmstream_functions[] = {
init_vgmstream_vsv, init_vgmstream_vsv,
init_vgmstream_ps2_pcm, init_vgmstream_ps2_pcm,
init_vgmstream_ps2_rkv, init_vgmstream_ps2_rkv,
init_vgmstream_ps2_vas,
init_vgmstream_ps2_vas_container,
init_vgmstream_lp_ap_lep, init_vgmstream_lp_ap_lep,
init_vgmstream_sdt, init_vgmstream_sdt,
init_vgmstream_aix, init_vgmstream_aix,
@ -142,7 +140,7 @@ init_vgmstream_t init_vgmstream_functions[] = {
init_vgmstream_ish_isd, init_vgmstream_ish_isd,
init_vgmstream_gsnd, init_vgmstream_gsnd,
init_vgmstream_ydsp, init_vgmstream_ydsp,
init_vgmstream_ngc_ssm, init_vgmstream_ssm,
init_vgmstream_ps2_joe, init_vgmstream_ps2_joe,
init_vgmstream_vgs, init_vgmstream_vgs,
init_vgmstream_dcs_wav, init_vgmstream_dcs_wav,
@ -524,11 +522,13 @@ init_vgmstream_t init_vgmstream_functions[] = {
init_vgmstream_gwb_gwd, init_vgmstream_gwb_gwd,
init_vgmstream_s_pack, init_vgmstream_s_pack,
init_vgmstream_cbx, init_vgmstream_cbx,
init_vgmstream_vas, init_vgmstream_vas_rockstar,
/* lower priority metas (no clean header identity, somewhat ambiguous, or need extension/companion file to identify) */ /* lower priority metas (no clean header identity, somewhat ambiguous, or need extension/companion file to identify) */
init_vgmstream_scd_pcm,
init_vgmstream_agsc, init_vgmstream_agsc,
init_vgmstream_scd_pcm,
init_vgmstream_vas_kceo,
init_vgmstream_vas_kceo_container,
init_vgmstream_ps2_wmus, init_vgmstream_ps2_wmus,
init_vgmstream_mib_mih, init_vgmstream_mib_mih,
init_vgmstream_mjb_mjh, init_vgmstream_mjb_mjh,

View File

@ -131,6 +131,7 @@ typedef enum {
coding_SASSC, /* Activision EXAKT SASSC 8-bit DPCM */ coding_SASSC, /* Activision EXAKT SASSC 8-bit DPCM */
coding_DERF, /* DERF 8-bit DPCM */ coding_DERF, /* DERF 8-bit DPCM */
coding_WADY, /* WADY 8-bit DPCM */ coding_WADY, /* WADY 8-bit DPCM */
coding_DPCM_KCEJ, /* Konami Computer Entertainment Japan 8-bit DPCM */
coding_NWA, /* VisualArt's NWA DPCM */ coding_NWA, /* VisualArt's NWA DPCM */
coding_ACM, /* InterPlay ACM */ coding_ACM, /* InterPlay ACM */
coding_CIRCUS_ADPCM, /* Circus 8-bit ADPCM */ coding_CIRCUS_ADPCM, /* Circus 8-bit ADPCM */
@ -344,7 +345,7 @@ typedef enum {
meta_SCD_PCM, /* Lunar - Eternal Blue */ 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_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_RKV, /* Legacy of Kain - Blood Omen 2 (PS2) */
meta_PS2_VAS, /* Pro Baseball Spirits 5 */ meta_VAS_KCEO,
meta_LP_AP_LEP, meta_LP_AP_LEP,
meta_SDT, /* Baldur's Gate - Dark Alliance */ meta_SDT, /* Baldur's Gate - Dark Alliance */
meta_STR_SEGA, meta_STR_SEGA,
@ -364,7 +365,7 @@ typedef enum {
meta_FFCC_STR, /* Final Fantasy: Crystal Chronicles */ meta_FFCC_STR, /* Final Fantasy: Crystal Chronicles */
meta_UBI_JADE, /* Beyond Good & Evil, Rayman Raving Rabbids */ meta_UBI_JADE, /* Beyond Good & Evil, Rayman Raving Rabbids */
meta_GCA, /* Metal Slug Anthology */ meta_GCA, /* Metal Slug Anthology */
meta_NGC_SSM, /* Golden Gashbell Full Power */ meta_SSM,
meta_PS2_JOE, /* Wall-E / Pixar games */ meta_PS2_JOE, /* Wall-E / Pixar games */
meta_YMF, meta_YMF,
meta_SADL, meta_SADL,
@ -705,7 +706,7 @@ typedef enum {
meta_NXOF, meta_NXOF,
meta_GWB_GWD, meta_GWB_GWD,
meta_CBX, meta_CBX,
meta_VAS, meta_VAS_ROCKSTAR,
} meta_t; } meta_t;