Merge branch 'bnnm-lwma-vs-ads'

This commit is contained in:
Christopher Snowhill 2018-10-21 16:51:55 -07:00
commit 5f842f7edd
18 changed files with 244 additions and 89 deletions

View File

@ -121,39 +121,80 @@ standard, whose docs discuss extending M3U with arbitrary tags.
## Special cases ## Special cases
vgmstream aims to support most file formats as-is, but some files require extra vgmstream aims to support most audio formats as-is, but some files require extra
handling. handling.
### Renamed files ### Renamed files
A few extensions that vgmstream supports clash with common ones. Since players A few extensions that vgmstream supports clash with common ones. Since players
like foobar or Winamp don't react well to that, they may be renamed for like foobar or Winamp don't react well to that, they may be renamed to make
vgmstream (mainly to get looping in some cases). them playable through vgmstream.
- .aac to .laac - .aac to .laac (tri-Ace games)
- .ac3 to .lac3 - .ac3 to .lac3 (standard AC3)
- .aif to .aiffl or .aifcl - .aif to .aiffl or .aifcl (standard Mac AIF)
- .asf to .sng (EA formats) - .asf to .sng (EA games)
- .flac to .lflac - .flac to .lflac (standard FLAC)
- .mp4 to .lmp4 - .mp2 to .lmp2 (standard MP2)
- .ogg to .logg - .mp3 to .lmp3 (standard MP3)
- .opus to .lopus - .mp4 to .lmp4 (standard M4A)
- .stm to .lstm - .mpc to .lmpc (standard MPC)
- .wav to .lwav - .ogg to .logg (standard OGG)
- .opus to .lopus (standard OPUS or Switch OPUS)
- .stm to .lstm (Rockstar STM)
- .wav to .lwav (standard WAV)
- .wma to .lwma (standard WMA)
- .(any) to .vgmstream (FFmpeg formats or TXTH)
Command line tools don't have this restriction and will accept the original Command line tools don't have this restriction and will accept the original
filename. filename.
When extracting from a bigfile sometimes internal files don't have an actual The main advantage to rename them is that vgmstream may use the file's
internal loop info, or apply subtle fixes, but is also limited in some ways
(like standard/player's tagging).
.vgmstream is a catch-all extension that may work as a last resort to make
a file playable.
When extracting from a bigfile, sometimes internal files don't have an actual
name+extension. Those should be renamed to its proper/common extension, as the name+extension. Those should be renamed to its proper/common extension, as the
extractor program may guess wrong (like .wav instead of .at3 or .wem). If extractor program may guess wrong (like .wav instead of .at3 or .wem). If
there is no known extension usually the header id is used instead. there is no known extension, usually the header id string may be used instead.
### Loop assists Note that vgmstream also accepts certain extension-less files too.
### Demuxed videos
vgmstream also supports audio from videos, but usually must be demuxed (extracted
without modification) first, since vgmstream doesn't attempt to support them.
The easiest way to do this is using VGMToolBox's "Video Demultiplexer" option
for common game video formats (.bik, .vp6, .pss, .pam, .pmf, .usm, .xmv, etc).
For standard videos formats (.avi, .mp4, .webm, .m2v, .ogv, etc) not supported
by VGMToolBox FFmpeg binary may work:
- `ffmpeg.exe -i (input file) -vn -acodec copy (output file)`
Output extension may need to be adjusted to some appropriate audio file depending
on the audio codec used. ffprobe.exe can list this codec, though the correct audio
extension depends on the video itself (like .avi to .wav/mp2/mp3 or .ogv to .ogg).
Some games use custom video formats, demuxer scripts in .bms format may be found
on the internet.
### Companion files
Some formats have companion files with external looping info, and should be Some formats have companion files with external looping info, and should be
left together. left together.
- .mus (playlist for .acm) - .mus (playlist for .acm)
- .pos (loop info for .wav: 32 bit LE loop start sample + loop end sample) - .pos (loop info for .wav, and sometimes .ogg)
- .sli (loop info for .ogg) - .ogg.sli or .sli (loop info for .ogg)
- .sfl (loop info for .ogg) - .ogg.sfl (loop info for .ogg)
- .vgmstream + .pos (FFmpeg formats + loop assist) - .vgmstream.pos (loop info for FFmpeg formats)
- also possible for certain extensions like .lflac.pos
Similarly some formats split header and/or data in separate files (.sgh+sgd,
.wav.str+.wav, (file)_L.dsp+(file)_R.dsp, etc). vgmstream will also detect
and use those as needed and must be tegether, even if only one of the two
will be used to play.
.pos is a small file with 32 bit little endian values: loop start sample
and loop end sample. For FFmpeg formats (.vgmstream.pos) it may optionally
have total samples after those.
### Decryption keys ### Decryption keys
Certain formats have encrypted data, and need a key to decrypt. vgmstream Certain formats have encrypted data, and need a key to decrypt. vgmstream
@ -162,7 +203,7 @@ a companion file:
- .adx: .adxkey (derived 6 byte key, in start/mult/add format) - .adx: .adxkey (derived 6 byte key, in start/mult/add format)
- .ahx: .ahxkey (derived 6 byte key, in start/mult/add format) - .ahx: .ahxkey (derived 6 byte key, in start/mult/add format)
- .hca: .hcakey (8 byte decryption key, a 64-bit number) - .hca: .hcakey (8 byte decryption key, a 64-bit number)
- May be followed by 2 byte AWB derivation value for newer HCA - May be followed by 2 byte AWB scramble key for newer HCA
- .fsb: .fsbkey (decryption key, in hex) - .fsb: .fsbkey (decryption key, in hex)
The key file can be ".(ext)key" (for the whole folder), or "(name).(ext)key" The key file can be ".(ext)key" (for the whole folder), or "(name).(ext)key"
@ -187,6 +228,9 @@ file, or static values.
filenames to play as one (ex. "intro.vag" "loop.vag"), name with subsong index filenames to play as one (ex. "intro.vag" "loop.vag"), name with subsong index
(ex. bgm.sxd#10), or mask channels to only play some (ex. "song.adx#c1,2"). (ex. bgm.sxd#10), or mask channels to only play some (ex. "song.adx#c1,2").
Creation of those files is meant for advanced users, docs can be found in
vgmstream source.
## Supported codec types ## Supported codec types
Quick list of codecs vgmstream supports, including many obscure ones that Quick list of codecs vgmstream supports, including many obscure ones that
@ -241,7 +285,7 @@ are used in few games.
- AAC - AAC
- Bink - Bink
- AC3/SPDIF - AC3/SPDIF
- Xiph Opus (Ogg, Switch, EA, UE4) - Xiph Opus (Ogg, Switch, EA, UE4, Exient)
- Xiph CELT (FSB) - Xiph CELT (FSB)
- Musepack - Musepack
- FLAC - FLAC
@ -494,6 +538,6 @@ This list is not complete and many other files are supported.
- .ahxkey (decryption key for .ahx, in start/mult/add format) - .ahxkey (decryption key for .ahx, in start/mult/add format)
- .hcakey (decryption key for .hca, in HCA Decoder format) - .hcakey (decryption key for .hca, in HCA Decoder format)
- .fsbkey (decryption key for .fsb, in hex) - .fsbkey (decryption key for .fsb, in hex)
- .vgmstream + .pos (FFmpeg formats + loop assist) - .vgmstream + .vgmstream.pos (FFmpeg formats + loop assist)
Enjoy! *hcs* Enjoy! *hcs*

View File

@ -288,7 +288,6 @@ size_t switch_opus_get_samples(off_t offset, size_t data_size, STREAMFILE *strea
size_t switch_opus_get_encoder_delay(off_t offset, STREAMFILE *streamFile); size_t switch_opus_get_encoder_delay(off_t offset, STREAMFILE *streamFile);
size_t ue4_opus_get_encoder_delay(off_t offset, STREAMFILE *streamFile); size_t ue4_opus_get_encoder_delay(off_t offset, STREAMFILE *streamFile);
size_t ea_opus_get_encoder_delay(off_t offset, STREAMFILE *streamFile); size_t ea_opus_get_encoder_delay(off_t offset, STREAMFILE *streamFile);
size_t x_opus_get_encoder_delay(off_t offset, STREAMFILE *streamFile);
#endif #endif

View File

@ -594,9 +594,6 @@ size_t ue4_opus_get_encoder_delay(off_t offset, STREAMFILE *streamFile) {
size_t ea_opus_get_encoder_delay(off_t offset, STREAMFILE *streamFile) { size_t ea_opus_get_encoder_delay(off_t offset, STREAMFILE *streamFile) {
return custom_opus_get_encoder_delay(offset, streamFile, OPUS_EA); return custom_opus_get_encoder_delay(offset, streamFile, OPUS_EA);
} }
size_t x_opus_get_encoder_delay(off_t offset, STREAMFILE *streamFile) {
return custom_opus_get_encoder_delay(offset, streamFile, OPUS_X);
}
static size_t get_xopus_packet_size(int packet, STREAMFILE * streamfile) { static size_t get_xopus_packet_size(int packet, STREAMFILE * streamfile) {

View File

@ -1,11 +1,13 @@
#include "vgmstream.h" #include "vgmstream.h"
/* defines the list of accepted extensions. vgmstream doesn't use it internally so it's here /* Defines the list of accepted extensions. vgmstream doesn't use it internally so it's here
* to inform plugins that need it. Common extensions are commented out to avoid stealing them. */ * to inform plugins that need it. Common extensions are commented out to avoid stealing them. */
/* some extensions require external libraries and could be #ifdef, not really needed */ /* Some extensions require external libraries and could be #ifdef, not worth. */
/* some formats marked as "not parsed" mean they'll go through FFmpeg, the header/extension is not parsed */
/* Formats marked as "not parsed" mean they'll go through FFmpeg, the header/extension isn't
* parsed by vgmstream and typically won't not be fully accurate. May have a .ext.pos pair for fun. */
static const char* extension_list[] = { static const char* extension_list[] = {
@ -16,20 +18,21 @@ static const char* extension_list[] = {
"2pfs", "2pfs",
"800", "800",
//"aac", //common, also tri-Ace's //"aac", //common
"aa3", //FFmpeg, not parsed (ATRAC3/ATRAC3PLUS/MP3/LPCM/WMA) "aa3", //FFmpeg/not parsed (ATRAC3/ATRAC3PLUS/MP3/LPCM/WMA)
"aaap", "aaap",
"aax", "aax",
"abk", "abk",
//"ac3", //FFmpeg, not parsed //common? //"ac3", //common, FFmpeg/not parsed (AC3)
"ace", //fake, for tri-Ace's formats (to be removed) "ace", //fake extension for tri-Ace's .aac (renamed, to be removed)
"acm", "acm",
"ad", //txth/reserved [Xenosaga Freaks (PS2)] "ad", //txth/reserved [Xenosaga Freaks (PS2)]
"adc", //txth/reserved [Tomb Raider The Last Revelation(DC), Tomb Raider Chronicles(DC)] "adc", //txth/reserved [Tomb Raider The Last Revelation (DC), Tomb Raider Chronicles (DC)]
"adm", "adm",
"adp", "adp",
"adpcm", "adpcm",
"ads", "ads",
"adw",
"adx", "adx",
"afc", "afc",
"agsc", "agsc",
@ -38,13 +41,13 @@ static const char* extension_list[] = {
"ai", "ai",
//"aif", //common //"aif", //common
"aifc", //common? "aifc", //common?
"aifcl", //fake extension, for AIF??? "aifcl", //fake extension for .aif???
//"aiff", //common //"aiff", //common
"aiffl", //fake extension, for AIF??? "aiffl", //fake extension for .aif???
"aix", "aix",
"akb", "akb",
"al2", "al2",
"amts", //fake extension/header id for .stm (to be removed) "amts", //fake extension/header id for .stm (renamed? to be removed?)
"ao", "ao",
"apc", "apc",
"as4", "as4",
@ -73,7 +76,7 @@ static const char* extension_list[] = {
"bdsp", "bdsp",
"bfstm", "bfstm",
"bfwav", "bfwav",
"bfwavnsmbu", "bfwavnsmbu", //fake extension for New Super Smash Bros U (renamed to fix bug)
"bg00", "bg00",
"bgm", "bgm",
"bgw", "bgw",
@ -98,7 +101,7 @@ static const char* extension_list[] = {
"cbd2", "cbd2",
"ccc", "ccc",
"cd", "cd",
"cfn", //fake extension/header id for .caf (to be removed) "cfn", //fake extension for CAF (renamed, to be removed?)
"ckb", "ckb",
"ckd", "ckd",
"cks", "cks",
@ -133,6 +136,7 @@ static const char* extension_list[] = {
"fag", "fag",
"ffw", "ffw",
"filp", "filp",
//"flac", //common
"flx", "flx",
"fsb", "fsb",
"fsv", "fsv",
@ -163,7 +167,7 @@ static const char* extension_list[] = {
"iab", "iab",
"iadp", "iadp",
"idsp", "idsp",
"idvi", //fake extension for .pcm (to be removed) "idvi", //fake extension/header id for .pcm (renamed, to be removed)
"idx", "idx",
"ikm", "ikm",
"ild", "ild",
@ -180,30 +184,34 @@ static const char* extension_list[] = {
"jstm", "jstm",
"kces", "kces",
"kcey", //fake extension/header id (to be removed) "kcey", //fake extension/header id for .pcm (renamed, to be removed)
"khv", "khv",
"km9", "km9",
"kovs", //.kvs header id "kovs", //fake extension/header id for .kvs
"kns", "kns",
"kraw", "kraw",
"ktss", //.kns header id "ktss", //fake extension/header id for .kns
"kvs", "kvs",
"l", "l",
"laac", //fake extension, for AAC (tri-Ace/FFmpeg) "laac", //fake extension for .aac (tri-Ace)
"lac3", //fake extension, for AC3 "lac3", //fake extension for .ac3, FFmpeg/not parsed
"leg", "leg",
"lflac", //fake extension, FFmpeg, not parsed, use with .pos pair for fun "lflac", //fake extension for .flac, FFmpeg/not parsed
"lmp4", //fake extension, for MP4s "lmp2", //fake extension for .mp2, FFmpeg/not parsed
"logg", //fake extension, for OGGs "lmp3", //fake extension for .mp3, FFmpeg/not parsed
"lopus", //fake extension, for OPUS "lmp4", //fake extension for .mp4
"lmpc", //fake extension for .mpc, FFmpeg/not parsed
"logg", //fake extension for .ogg
"lopus", //fake extension for .opus
"lpcm", "lpcm",
"lpk", "lpk",
"lps", "lps",
"lse", "lse",
"lsf", "lsf",
"lstm", //fake extension, for STMs "lstm", //fake extension for .stm
"lwav", //fake extension, for WAVs "lwav", //fake extension for .wav
"lwma", //fake extension for .wma, FFmpeg/not parsed
"mab", "mab",
"matx", "matx",
@ -220,9 +228,10 @@ static const char* extension_list[] = {
"mihb", "mihb",
"mnstr", "mnstr",
"mogg", "mogg",
//"mp2", //common
//"mp3", //common //"mp3", //common
//"mp4", //common //"mp4", //common
//"mpc", //FFmpeg, not parsed (musepack) //common //"mpc", //common
"mpdsp", "mpdsp",
"mpds", "mpds",
"mps", //txth/reserved [Scandal (PS2)] "mps", //txth/reserved [Scandal (PS2)]
@ -239,7 +248,7 @@ static const char* extension_list[] = {
"mus", "mus",
"musc", "musc",
"musx", "musx",
"mvb", //txth/reserved [Porsche Challenge(PS1)] "mvb", //txth/reserved [Porsche Challenge (PS1)]
"mwv", "mwv",
"mxst", "mxst",
"myspd", "myspd",
@ -250,14 +259,14 @@ static const char* extension_list[] = {
"nlsd", "nlsd",
"nop", "nop",
"nps", "nps",
"npsf", //fake extension/header id for .nps (to be removed) "npsf", //fake extension/header id for .nps (in bigfiles)
"nus3bank", "nus3bank",
"nwa", "nwa",
"nxa", "nxa",
//"ogg", //common //"ogg", //common
"ogl", "ogl",
"oma", //FFmpeg, not parsed (ATRAC3/ATRAC3PLUS/MP3/LPCM/WMA) "oma", //FFmpeg/not parsed (ATRAC3/ATRAC3PLUS/MP3/LPCM/WMA)
"omu", "omu",
//"opus", //common //"opus", //common
"otm", "otm",
@ -274,10 +283,10 @@ static const char* extension_list[] = {
"pnb", "pnb",
"pona", "pona",
"pos", "pos",
"ps2stm", //fake extension for .stm (to be removed) "ps2stm", //fake extension for .stm (renamed? to be removed?)
"psh", // fake extension for VSV(?) Dawn of Mana needs to be checked again "psh", // fake extension for VSV(?) Dawn of Mana needs to be checked again
"psnd", "psnd",
"psw", //fake extension for .wam "psw", //fake extension for .wam (renamed, to be removed)
"r", "r",
"rac", //txth/reserved [Manhunt (Xbox)] "rac", //txth/reserved [Manhunt (Xbox)]
@ -293,7 +302,7 @@ static const char* extension_list[] = {
"rsd", "rsd",
"rsf", "rsf",
"rsm", "rsm",
"rstm", //rsm header id "rstm", //fake extension/header id for .rstm (in bigfiles)
"rvws", "rvws",
"rwar", "rwar",
"rwav", "rwav",
@ -335,7 +344,7 @@ static const char* extension_list[] = {
"sli", "sli",
"smc", "smc",
"smp", "smp",
"smpl", //fake extension (to be removed) "smpl", //fake extension/header id for .v0/v1 (renamed, to be removed)
"smv", "smv",
"snd", "snd",
"snds", "snds",
@ -357,7 +366,7 @@ static const char* extension_list[] = {
"ster", "ster",
"sth", "sth",
//"stm", //common //"stm", //common
"stma", //fake extension (to be removed) "stma", //fake extension/header id for .stm
"str", "str",
"stream", "stream",
"strm", "strm",
@ -393,7 +402,7 @@ static const char* extension_list[] = {
"v0", "v0",
//"v1", //dual channel with v0 //"v1", //dual channel with v0
"va3", //konami atrac3, FFMPEG - DDR Supernova 2 AC "va3",
"vag", "vag",
"vai", "vai",
"vas", "vas",
@ -430,6 +439,7 @@ static const char* extension_list[] = {
"wem", "wem",
"wii", "wii",
"wip", //txth/reserved [Colin McRae DiRT (PC)] "wip", //txth/reserved [Colin McRae DiRT (PC)]
"wma", //common
"wmus", "wmus",
"wp2", "wp2",
"wpd", "wpd",
@ -456,7 +466,7 @@ static const char* extension_list[] = {
"xss", "xss",
"xvag", "xvag",
"xvas", "xvas",
"xwav",//fake, to be removed "xwav",//fake extension for .wav (renamed, to be removed)
"xwb", "xwb",
"xmd", "xmd",
"xopus", "xopus",
@ -676,6 +686,7 @@ static const layout_info layout_info_list[] = {
{layout_blocked_sthd, "blocked (STHD)"}, {layout_blocked_sthd, "blocked (STHD)"},
{layout_blocked_h4m, "blocked (H4M)"}, {layout_blocked_h4m, "blocked (H4M)"},
{layout_blocked_xa_aiff, "blocked (XA AIFF)"}, {layout_blocked_xa_aiff, "blocked (XA AIFF)"},
{layout_blocked_vs_ffx, "blocked (Final Fantasy X VS)"},
}; };
static const meta_info meta_info_list[] = { static const meta_info meta_info_list[] = {
@ -1094,8 +1105,9 @@ static const meta_info meta_info_list[] = {
{meta_ADPCM_CAPCOM, "Capcom .ADPCM header"}, {meta_ADPCM_CAPCOM, "Capcom .ADPCM header"},
{meta_UE4OPUS, "Epic Games UE4OPUS header"}, {meta_UE4OPUS, "Epic Games UE4OPUS header"},
{meta_XWMA, "Microsoft XWMA RIFF header"}, {meta_XWMA, "Microsoft XWMA RIFF header"},
{meta_VA3, "Konami / Sony ATRAC3 Header" }, {meta_VA3, "Konami VA3 header" },
{meta_XOPUS, "Rovio XOPUS header"}, {meta_XOPUS, "Exient XOPUS header"},
{meta_VS_FFX, "Final Fantasy X VS header"},
}; };

View File

@ -205,6 +205,9 @@ void block_update(off_t block_offset, VGMSTREAM * vgmstream) {
case layout_blocked_xa_aiff: case layout_blocked_xa_aiff:
block_update_xa_aiff(block_offset,vgmstream); block_update_xa_aiff(block_offset,vgmstream);
break; break;
case layout_blocked_vs_ffx:
block_update_vs_ffx(block_offset,vgmstream);
break;
default: /* not a blocked layout */ default: /* not a blocked layout */
break; break;
} }

View File

@ -0,0 +1,26 @@
#include "layout.h"
#include "../vgmstream.h"
/* Final Fantasy X VS headered blocks */
void block_update_vs_ffx(off_t block_offset, VGMSTREAM * vgmstream) {
int i;
size_t block_size = 0x800;
/* 0x00: header id
* 0x04: null
* 0x08: block number
* 0x0c: blocks left in the subfile
* 0x10: always 0x1000
* 0x14: always 0x64
* 0x18: null
* 0x1c: null */
vgmstream->current_block_offset = block_offset;
vgmstream->current_block_size = block_size - 0x20;
vgmstream->next_block_offset = block_offset + block_size;
/* 0x08: number of remaning blocks, 0x10: some id/size? (shared in all blocks) */
for (i = 0; i < vgmstream->channels; i++) {
vgmstream->ch[i].offset = block_offset + 0x20 + 0x800*i;
}
}

View File

@ -46,6 +46,7 @@ void block_update_ea_wve_ad10(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_sthd(off_t block_offset, VGMSTREAM * vgmstream); void block_update_sthd(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_h4m(off_t block_offset, VGMSTREAM * vgmstream); void block_update_h4m(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_xa_aiff(off_t block_offset, VGMSTREAM * vgmstream); void block_update_xa_aiff(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_vs_ffx(off_t block_offset, VGMSTREAM * vgmstream);
/* other layouts */ /* other layouts */
void render_vgmstream_interleave(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream); void render_vgmstream_interleave(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);

View File

@ -1190,10 +1190,14 @@
RelativePath=".\meta\ps2_voi.c" RelativePath=".\meta\ps2_voi.c"
> >
</File> </File>
<File <File
RelativePath=".\meta\vpk.c" RelativePath=".\meta\vpk.c"
> >
</File> </File>
<File
RelativePath=".\meta\vs_ffx.c"
>
</File>
<File <File
RelativePath=".\meta\ps2_wad.c" RelativePath=".\meta\ps2_wad.c"
> >
@ -1946,6 +1950,10 @@
RelativePath=".\layout\blocked_vgs.c" RelativePath=".\layout\blocked_vgs.c"
> >
</File> </File>
<File
RelativePath=".\layout\blocked_vs_ffx.c"
>
</File>
<File <File
RelativePath=".\layout\blocked_xvag.c" RelativePath=".\layout\blocked_xvag.c"
> >

View File

@ -391,6 +391,7 @@
<ClCompile Include="meta\ps2_vms.c" /> <ClCompile Include="meta\ps2_vms.c" />
<ClCompile Include="meta\ps2_voi.c" /> <ClCompile Include="meta\ps2_voi.c" />
<ClCompile Include="meta\vpk.c" /> <ClCompile Include="meta\vpk.c" />
<ClCompile Include="meta\vs_ffx.c" />
<ClCompile Include="meta\ps2_wad.c" /> <ClCompile Include="meta\ps2_wad.c" />
<ClCompile Include="meta\ps2_wb.c" /> <ClCompile Include="meta\ps2_wb.c" />
<ClCompile Include="meta\ps2_xa2.c" /> <ClCompile Include="meta\ps2_xa2.c" />
@ -534,6 +535,7 @@
<ClCompile Include="layout\blocked_awc.c" /> <ClCompile Include="layout\blocked_awc.c" />
<ClCompile Include="layout\blocked_ea_1snh.c" /> <ClCompile Include="layout\blocked_ea_1snh.c" />
<ClCompile Include="layout\blocked_vgs.c" /> <ClCompile Include="layout\blocked_vgs.c" />
<ClCompile Include="layout\blocked_vs_ffx.c" />
<ClCompile Include="layout\blocked_vawx.c" /> <ClCompile Include="layout\blocked_vawx.c" />
<ClCompile Include="layout\blocked_xvag.c" /> <ClCompile Include="layout\blocked_xvag.c" />
<ClCompile Include="layout\blocked_caf.c" /> <ClCompile Include="layout\blocked_caf.c" />

View File

@ -742,6 +742,9 @@
<ClCompile Include="meta\vpk.c"> <ClCompile Include="meta\vpk.c">
<Filter>meta\Source Files</Filter> <Filter>meta\Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="meta\vs_ffx.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\ps2_wad.c"> <ClCompile Include="meta\ps2_wad.c">
<Filter>meta\Source Files</Filter> <Filter>meta\Source Files</Filter>
</ClCompile> </ClCompile>
@ -1165,6 +1168,9 @@
<ClCompile Include="layout\blocked_vgs.c"> <ClCompile Include="layout\blocked_vgs.c">
<Filter>layout\Source Files</Filter> <Filter>layout\Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="layout\blocked_vs_ffx.c">
<Filter>layout\Source Files</Filter>
</ClCompile>
<ClCompile Include="layout\blocked_vawx.c"> <ClCompile Include="layout\blocked_vawx.c">
<Filter>layout\Source Files</Filter> <Filter>layout\Source Files</Filter>
</ClCompile> </ClCompile>

View File

@ -4,8 +4,8 @@
#include "hca_keys_awb.h" #include "hca_keys_awb.h"
typedef struct { typedef struct {
uint64_t key; /* hca key or seed key */ uint64_t key; /* hca key or seed ('user') key */
const uint16_t *subkeys; /* derivation subkey table for seed key */ const uint16_t *subkeys; /* scramble subkey table for seed key */
size_t subkeys_size; /* size of the derivation subkey table */ size_t subkeys_size; /* size of the derivation subkey table */
} hcakey_info; } hcakey_info;
@ -15,7 +15,7 @@ typedef struct {
* CRI's tools expect an unsigned 64 bit number string, but keys are commonly found online in hex form. * CRI's tools expect an unsigned 64 bit number string, but keys are commonly found online in hex form.
* Keys only use 56 bits though, so the upper 8 bits can be ignored. * Keys only use 56 bits though, so the upper 8 bits can be ignored.
* *
* ACB+AWB after mid 2018 use a master seed key + a derivation subkey in the AWB (normally 16b LE at 0x0e) * ACB+AWB after mid 2018 use a user seed key + a scramble subkey in the AWB (normally 16b LE at 0x0e)
* to create the final HCA key, which means there is one key per AWB (so most HCA have a unique key). * to create the final HCA key, which means there is one key per AWB (so most HCA have a unique key).
* vgmstream derives the key if subkey table is provided. * vgmstream derives the key if subkey table is provided.
*/ */

View File

@ -799,4 +799,6 @@ VGMSTREAM * init_vgmstream_xwma(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_xopus(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_xopus(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_vs_ffx(STREAMFILE * streamFile);
#endif /*_META_H*/ #endif /*_META_H*/

View File

@ -150,10 +150,11 @@ VGMSTREAM * init_vgmstream_ps2_ads(STREAMFILE *streamFile) {
loop_start_sample = loop_start / 2 / channel_count; loop_start_sample = loop_start / 2 / channel_count;
is_loop_samples = 1; is_loop_samples = 1;
} }
else if ((loop_start % 0x800 == 0) && loop_start > 0) {/* sector-aligned, min is 0x800 */ else if ((loop_start % 0x800 == 0) && loop_start > 0) {/* sector-aligned, min/0 is 0x800 */
/* cavia games: loop_start is offset [Drakengard 1/2, GITS: Stand Alone Complex] */ /* cavia games: loop_start is offset [Drakengard 1/2, GITS: Stand Alone Complex] */
/* offset is absolute from the "cavia stream format" container that adjusts ADS start */
loop_flag = 1; loop_flag = 1;
loop_start_offset = loop_start; loop_start_offset = loop_start - 0x800;
ignore_silent_frame_cavia = 1; ignore_silent_frame_cavia = 1;
} }
else if (loop_start % 0x800 != 0 || loop_start == 0) { /* not sector aligned */ else if (loop_start % 0x800 != 0 || loop_start == 0) { /* not sector aligned */

View File

@ -273,8 +273,9 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
* .adp: Headhunter (DC) * .adp: Headhunter (DC)
* .xss: Spider-Man The Movie (Xbox) * .xss: Spider-Man The Movie (Xbox)
* .xsew: Mega Man X Legacy Collections (PC) * .xsew: Mega Man X Legacy Collections (PC)
* .adpcm: Angry Birds Transformers (Android) */ * .adpcm: Angry Birds Transformers (Android)
if ( check_extensions(streamFile, "wav,lwav,xwav,da,dax,cd,med,snd,adx,adp,xss,xsew,adpcm") ) { * .adw: Dead Rising 2 (PC) */
if ( check_extensions(streamFile, "wav,lwav,xwav,da,dax,cd,med,snd,adx,adp,xss,xsew,adpcm,adw") ) {
; ;
} }
else if ( check_extensions(streamFile, "mwv") ) { else if ( check_extensions(streamFile, "mwv") ) {

53
src/meta/vs_ffx.c Normal file
View File

@ -0,0 +1,53 @@
#include "meta.h"
#include "../layout/layout.h"
#include "../coding/coding.h"
/* .vs/VS - from Final Fantasy X voices (PS2) */
VGMSTREAM * init_vgmstream_vs_ffx(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
int channel_count, loop_flag;
off_t start_offset;
/* checks */
/* .vs: header id (probably ok like The Bouncer's .vs, very similar) */
if (!check_extensions(streamFile, "vs"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x56530000) /* "VS\0\0" */
goto fail;
loop_flag = 0;
channel_count = 1;
start_offset = 0x00;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_VS_FFX;
vgmstream->sample_rate = 48000;
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_blocked_vs_ffx;
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
/* calc num_samples */
{
vgmstream->next_block_offset = start_offset;
do {
block_update(vgmstream->next_block_offset,vgmstream);
vgmstream->num_samples += ps_bytes_to_samples(vgmstream->current_block_size, 1);
}
while (vgmstream->next_block_offset < get_streamfile_size(streamFile));
block_update(start_offset, vgmstream);
}
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -2,7 +2,7 @@
#include "../coding/coding.h" #include "../coding/coding.h"
/* XOPUS - from Rovio games [Angry Birds: Transformers (Android), Angry Birds: Go (Android)] */ /* XOPUS - from Exient games [Angry Birds: Transformers (Android), Angry Birds: Go (Android)] */
VGMSTREAM * init_vgmstream_xopus(STREAMFILE *streamFile) { VGMSTREAM * init_vgmstream_xopus(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL; VGMSTREAM * vgmstream = NULL;
off_t start_offset; off_t start_offset;
@ -17,24 +17,21 @@ VGMSTREAM * init_vgmstream_xopus(STREAMFILE *streamFile) {
if (read_32bitBE(0x00, streamFile) != 0x584F7075) /* "XOpu" */ if (read_32bitBE(0x00, streamFile) != 0x584F7075) /* "XOpu" */
goto fail; goto fail;
/* 0x04: always 1? 0x30? */ /* 0x04: always 0x01? */
channel_count = read_8bit(0x05, streamFile); channel_count = read_8bit(0x05, streamFile);
/* 0x06: always 0x30? */ /* 0x06: always 0x30? */
/* 0x08: always 0xc8? encoder delay? */ /* 0x08: always 0xc8? max allowed packet size? */
num_samples = read_32bitLE(0x0c, streamFile); num_samples = read_32bitLE(0x0c, streamFile);
/* 0x10: always 0x138? max packet size? */ skip = read_32bitLE(0x10, streamFile);
entries = read_32bitLE(0x14, streamFile); /* packet sizes */ entries = read_32bitLE(0x14, streamFile);
/* 0x18: data size */ data_size = read_32bitLE(0x18, streamFile);
/* 0x1c: unused */ /* 0x1c: unused */
/* 0x20+: packet sizes table */ /* 0x20+: packet sizes table */
sample_rate = 48000; sample_rate = 48000;
loop_flag = 0; loop_flag = 0;
start_offset = 0x20 + 0x02*entries; start_offset = 0x20 + 0x02*entries;
data_size = get_streamfile_size(streamFile) - start_offset;
skip = x_opus_get_encoder_delay(start_offset, streamFile);
/* build the VGMSTREAM */ /* build the VGMSTREAM */
@ -43,7 +40,7 @@ VGMSTREAM * init_vgmstream_xopus(STREAMFILE *streamFile) {
vgmstream->meta_type = meta_XOPUS; vgmstream->meta_type = meta_XOPUS;
vgmstream->sample_rate = sample_rate; vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = num_samples /*- skip*/; vgmstream->num_samples = num_samples;
#ifdef VGM_USE_FFMPEG #ifdef VGM_USE_FFMPEG
{ {

View File

@ -444,7 +444,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_ue4opus, init_vgmstream_ue4opus,
init_vgmstream_xwma, init_vgmstream_xwma,
init_vgmstream_xopus, init_vgmstream_xopus,
init_vgmstream_vs_ffx,
/* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */ /* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */
init_vgmstream_txth, /* proper parsers should supersede TXTH, once added */ init_vgmstream_txth, /* proper parsers should supersede TXTH, once added */
@ -1018,6 +1018,7 @@ void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstre
case layout_blocked_sthd: case layout_blocked_sthd:
case layout_blocked_h4m: case layout_blocked_h4m:
case layout_blocked_xa_aiff: case layout_blocked_xa_aiff:
case layout_blocked_vs_ffx:
render_vgmstream_blocked(buffer,sample_count,vgmstream); render_vgmstream_blocked(buffer,sample_count,vgmstream);
break; break;
case layout_aix: case layout_aix:

View File

@ -253,6 +253,7 @@ typedef enum {
layout_blocked_sthd, /* Dream Factory STHD */ layout_blocked_sthd, /* Dream Factory STHD */
layout_blocked_h4m, /* H4M video */ layout_blocked_h4m, /* H4M video */
layout_blocked_xa_aiff, /* XA in AIFF files [Crusader: No Remorse (SAT), Road Rash (3DO)] */ layout_blocked_xa_aiff, /* XA in AIFF files [Crusader: No Remorse (SAT), Road Rash (3DO)] */
layout_blocked_vs_ffx,
/* otherwise odd */ /* otherwise odd */
layout_aix, /* CRI AIX's wheels within wheels */ layout_aix, /* CRI AIX's wheels within wheels */
@ -701,6 +702,7 @@ typedef enum {
meta_XWMA, meta_XWMA,
meta_VA3, /* DDR Supernova 2 AC */ meta_VA3, /* DDR Supernova 2 AC */
meta_XOPUS, meta_XOPUS,
meta_VS_FFX,
} meta_t; } meta_t;