diff --git a/README.md b/README.md
index 451c81e7..f0a71746 100644
--- a/README.md
+++ b/README.md
@@ -121,39 +121,80 @@ standard, whose docs discuss extending M3U with arbitrary tags.
## 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.
### Renamed files
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
-vgmstream (mainly to get looping in some cases).
-- .aac to .laac
-- .ac3 to .lac3
-- .aif to .aiffl or .aifcl
-- .asf to .sng (EA formats)
-- .flac to .lflac
-- .mp4 to .lmp4
-- .ogg to .logg
-- .opus to .lopus
-- .stm to .lstm
-- .wav to .lwav
+like foobar or Winamp don't react well to that, they may be renamed to make
+them playable through vgmstream.
+- .aac to .laac (tri-Ace games)
+- .ac3 to .lac3 (standard AC3)
+- .aif to .aiffl or .aifcl (standard Mac AIF)
+- .asf to .sng (EA games)
+- .flac to .lflac (standard FLAC)
+- .mp2 to .lmp2 (standard MP2)
+- .mp3 to .lmp3 (standard MP3)
+- .mp4 to .lmp4 (standard M4A)
+- .mpc to .lmpc (standard MPC)
+- .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
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
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
left together.
- .mus (playlist for .acm)
-- .pos (loop info for .wav: 32 bit LE loop start sample + loop end sample)
-- .sli (loop info for .ogg)
-- .sfl (loop info for .ogg)
-- .vgmstream + .pos (FFmpeg formats + loop assist)
+- .pos (loop info for .wav, and sometimes .ogg)
+- .ogg.sli or .sli (loop info for .ogg)
+- .ogg.sfl (loop info for .ogg)
+- .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
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)
- .ahx: .ahxkey (derived 6 byte key, in start/mult/add format)
- .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)
The key file can be ".(ext)key" (for the whole folder), or "(name).(ext)key"
@@ -182,11 +223,14 @@ Programs like VGMToolbox can help to create GENH.
".txth" or ".(ext).txth" (for the whole folder), or "(name.ext).txth" (for a
single file). Contains dynamic text commands to read data from the original
file, or static values.
-
+
**TXTP**: a text playlist that works as a single song. Can contain a list of
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").
+Creation of those files is meant for advanced users, docs can be found in
+vgmstream source.
+
## Supported codec types
Quick list of codecs vgmstream supports, including many obscure ones that
@@ -241,7 +285,7 @@ are used in few games.
- AAC
- Bink
- AC3/SPDIF
-- Xiph Opus (Ogg, Switch, EA, UE4)
+- Xiph Opus (Ogg, Switch, EA, UE4, Exient)
- Xiph CELT (FSB)
- Musepack
- FLAC
@@ -250,7 +294,7 @@ are used in few games.
Note that vgmstream doesn't (can't) reproduce in-game music 1:1, as internal
resampling, filters, volume, etc, are not replicated. Some codecs are not
fully accurate compared to the games due to minor bugs, but in most cases
-it isn't audible.
+it isn't audible.
## Supported file types
@@ -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)
- .hcakey (decryption key for .hca, in HCA Decoder format)
- .fsbkey (decryption key for .fsb, in hex)
- - .vgmstream + .pos (FFmpeg formats + loop assist)
+ - .vgmstream + .vgmstream.pos (FFmpeg formats + loop assist)
Enjoy! *hcs*
diff --git a/src/coding/coding.h b/src/coding/coding.h
index 9070c43f..6dcd1784 100644
--- a/src/coding/coding.h
+++ b/src/coding/coding.h
@@ -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 ue4_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
diff --git a/src/coding/ffmpeg_decoder_custom_opus.c b/src/coding/ffmpeg_decoder_custom_opus.c
index 15707495..1203ece0 100644
--- a/src/coding/ffmpeg_decoder_custom_opus.c
+++ b/src/coding/ffmpeg_decoder_custom_opus.c
@@ -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) {
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) {
diff --git a/src/formats.c b/src/formats.c
index 30d15c1b..fb2fc8bd 100644
--- a/src/formats.c
+++ b/src/formats.c
@@ -1,11 +1,13 @@
#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. */
-/* some extensions require external libraries and could be #ifdef, not really needed */
-/* some formats marked as "not parsed" mean they'll go through FFmpeg, the header/extension is not parsed */
+/* Some extensions require external libraries and could be #ifdef, not worth. */
+
+/* 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[] = {
@@ -16,20 +18,21 @@ static const char* extension_list[] = {
"2pfs",
"800",
- //"aac", //common, also tri-Ace's
- "aa3", //FFmpeg, not parsed (ATRAC3/ATRAC3PLUS/MP3/LPCM/WMA)
+ //"aac", //common
+ "aa3", //FFmpeg/not parsed (ATRAC3/ATRAC3PLUS/MP3/LPCM/WMA)
"aaap",
"aax",
"abk",
- //"ac3", //FFmpeg, not parsed //common?
- "ace", //fake, for tri-Ace's formats (to be removed)
+ //"ac3", //common, FFmpeg/not parsed (AC3)
+ "ace", //fake extension for tri-Ace's .aac (renamed, to be removed)
"acm",
"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",
"adp",
"adpcm",
"ads",
+ "adw",
"adx",
"afc",
"agsc",
@@ -38,13 +41,13 @@ static const char* extension_list[] = {
"ai",
//"aif", //common
"aifc", //common?
- "aifcl", //fake extension, for AIF???
+ "aifcl", //fake extension for .aif???
//"aiff", //common
- "aiffl", //fake extension, for AIF???
+ "aiffl", //fake extension for .aif???
"aix",
"akb",
"al2",
- "amts", //fake extension/header id for .stm (to be removed)
+ "amts", //fake extension/header id for .stm (renamed? to be removed?)
"ao",
"apc",
"as4",
@@ -73,7 +76,7 @@ static const char* extension_list[] = {
"bdsp",
"bfstm",
"bfwav",
- "bfwavnsmbu",
+ "bfwavnsmbu", //fake extension for New Super Smash Bros U (renamed to fix bug)
"bg00",
"bgm",
"bgw",
@@ -98,7 +101,7 @@ static const char* extension_list[] = {
"cbd2",
"ccc",
"cd",
- "cfn", //fake extension/header id for .caf (to be removed)
+ "cfn", //fake extension for CAF (renamed, to be removed?)
"ckb",
"ckd",
"cks",
@@ -133,6 +136,7 @@ static const char* extension_list[] = {
"fag",
"ffw",
"filp",
+ //"flac", //common
"flx",
"fsb",
"fsv",
@@ -163,7 +167,7 @@ static const char* extension_list[] = {
"iab",
"iadp",
"idsp",
- "idvi", //fake extension for .pcm (to be removed)
+ "idvi", //fake extension/header id for .pcm (renamed, to be removed)
"idx",
"ikm",
"ild",
@@ -180,30 +184,34 @@ static const char* extension_list[] = {
"jstm",
"kces",
- "kcey", //fake extension/header id (to be removed)
+ "kcey", //fake extension/header id for .pcm (renamed, to be removed)
"khv",
"km9",
- "kovs", //.kvs header id
+ "kovs", //fake extension/header id for .kvs
"kns",
"kraw",
- "ktss", //.kns header id
+ "ktss", //fake extension/header id for .kns
"kvs",
"l",
- "laac", //fake extension, for AAC (tri-Ace/FFmpeg)
- "lac3", //fake extension, for AC3
+ "laac", //fake extension for .aac (tri-Ace)
+ "lac3", //fake extension for .ac3, FFmpeg/not parsed
"leg",
- "lflac", //fake extension, FFmpeg, not parsed, use with .pos pair for fun
- "lmp4", //fake extension, for MP4s
- "logg", //fake extension, for OGGs
- "lopus", //fake extension, for OPUS
+ "lflac", //fake extension for .flac, FFmpeg/not parsed
+ "lmp2", //fake extension for .mp2, FFmpeg/not parsed
+ "lmp3", //fake extension for .mp3, FFmpeg/not parsed
+ "lmp4", //fake extension for .mp4
+ "lmpc", //fake extension for .mpc, FFmpeg/not parsed
+ "logg", //fake extension for .ogg
+ "lopus", //fake extension for .opus
"lpcm",
"lpk",
"lps",
"lse",
"lsf",
- "lstm", //fake extension, for STMs
- "lwav", //fake extension, for WAVs
+ "lstm", //fake extension for .stm
+ "lwav", //fake extension for .wav
+ "lwma", //fake extension for .wma, FFmpeg/not parsed
"mab",
"matx",
@@ -220,9 +228,10 @@ static const char* extension_list[] = {
"mihb",
"mnstr",
"mogg",
+ //"mp2", //common
//"mp3", //common
//"mp4", //common
- //"mpc", //FFmpeg, not parsed (musepack) //common
+ //"mpc", //common
"mpdsp",
"mpds",
"mps", //txth/reserved [Scandal (PS2)]
@@ -239,7 +248,7 @@ static const char* extension_list[] = {
"mus",
"musc",
"musx",
- "mvb", //txth/reserved [Porsche Challenge(PS1)]
+ "mvb", //txth/reserved [Porsche Challenge (PS1)]
"mwv",
"mxst",
"myspd",
@@ -250,14 +259,14 @@ static const char* extension_list[] = {
"nlsd",
"nop",
"nps",
- "npsf", //fake extension/header id for .nps (to be removed)
+ "npsf", //fake extension/header id for .nps (in bigfiles)
"nus3bank",
"nwa",
"nxa",
//"ogg", //common
"ogl",
- "oma", //FFmpeg, not parsed (ATRAC3/ATRAC3PLUS/MP3/LPCM/WMA)
+ "oma", //FFmpeg/not parsed (ATRAC3/ATRAC3PLUS/MP3/LPCM/WMA)
"omu",
//"opus", //common
"otm",
@@ -274,10 +283,10 @@ static const char* extension_list[] = {
"pnb",
"pona",
"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
"psnd",
- "psw", //fake extension for .wam
+ "psw", //fake extension for .wam (renamed, to be removed)
"r",
"rac", //txth/reserved [Manhunt (Xbox)]
@@ -293,7 +302,7 @@ static const char* extension_list[] = {
"rsd",
"rsf",
"rsm",
- "rstm", //rsm header id
+ "rstm", //fake extension/header id for .rstm (in bigfiles)
"rvws",
"rwar",
"rwav",
@@ -335,7 +344,7 @@ static const char* extension_list[] = {
"sli",
"smc",
"smp",
- "smpl", //fake extension (to be removed)
+ "smpl", //fake extension/header id for .v0/v1 (renamed, to be removed)
"smv",
"snd",
"snds",
@@ -357,7 +366,7 @@ static const char* extension_list[] = {
"ster",
"sth",
//"stm", //common
- "stma", //fake extension (to be removed)
+ "stma", //fake extension/header id for .stm
"str",
"stream",
"strm",
@@ -393,7 +402,7 @@ static const char* extension_list[] = {
"v0",
//"v1", //dual channel with v0
- "va3", //konami atrac3, FFMPEG - DDR Supernova 2 AC
+ "va3",
"vag",
"vai",
"vas",
@@ -430,6 +439,7 @@ static const char* extension_list[] = {
"wem",
"wii",
"wip", //txth/reserved [Colin McRae DiRT (PC)]
+ "wma", //common
"wmus",
"wp2",
"wpd",
@@ -456,7 +466,7 @@ static const char* extension_list[] = {
"xss",
"xvag",
"xvas",
- "xwav",//fake, to be removed
+ "xwav",//fake extension for .wav (renamed, to be removed)
"xwb",
"xmd",
"xopus",
@@ -676,6 +686,7 @@ static const layout_info layout_info_list[] = {
{layout_blocked_sthd, "blocked (STHD)"},
{layout_blocked_h4m, "blocked (H4M)"},
{layout_blocked_xa_aiff, "blocked (XA AIFF)"},
+ {layout_blocked_vs_ffx, "blocked (Final Fantasy X VS)"},
};
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_UE4OPUS, "Epic Games UE4OPUS header"},
{meta_XWMA, "Microsoft XWMA RIFF header"},
- {meta_VA3, "Konami / Sony ATRAC3 Header" },
- {meta_XOPUS, "Rovio XOPUS header"},
+ {meta_VA3, "Konami VA3 header" },
+ {meta_XOPUS, "Exient XOPUS header"},
+ {meta_VS_FFX, "Final Fantasy X VS header"},
};
diff --git a/src/layout/blocked.c b/src/layout/blocked.c
index fe88a5cf..abe7e595 100644
--- a/src/layout/blocked.c
+++ b/src/layout/blocked.c
@@ -205,6 +205,9 @@ void block_update(off_t block_offset, VGMSTREAM * vgmstream) {
case layout_blocked_xa_aiff:
block_update_xa_aiff(block_offset,vgmstream);
break;
+ case layout_blocked_vs_ffx:
+ block_update_vs_ffx(block_offset,vgmstream);
+ break;
default: /* not a blocked layout */
break;
}
diff --git a/src/layout/blocked_vs_ffx.c b/src/layout/blocked_vs_ffx.c
new file mode 100644
index 00000000..7c7c620b
--- /dev/null
+++ b/src/layout/blocked_vs_ffx.c
@@ -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;
+ }
+}
diff --git a/src/layout/layout.h b/src/layout/layout.h
index f547d677..a1431a17 100644
--- a/src/layout/layout.h
+++ b/src/layout/layout.h
@@ -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_h4m(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 */
void render_vgmstream_interleave(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
diff --git a/src/libvgmstream.vcproj b/src/libvgmstream.vcproj
index e35bbf21..660cb833 100644
--- a/src/libvgmstream.vcproj
+++ b/src/libvgmstream.vcproj
@@ -1190,10 +1190,14 @@
RelativePath=".\meta\ps2_voi.c"
>
-
-
+
+
+
+
@@ -1946,6 +1950,10 @@
RelativePath=".\layout\blocked_vgs.c"
>
+
+
diff --git a/src/libvgmstream.vcxproj b/src/libvgmstream.vcxproj
index 6894f9f1..02a9376c 100644
--- a/src/libvgmstream.vcxproj
+++ b/src/libvgmstream.vcxproj
@@ -391,6 +391,7 @@
+
@@ -534,6 +535,7 @@
+
diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters
index b18770fa..74f584ab 100644
--- a/src/libvgmstream.vcxproj.filters
+++ b/src/libvgmstream.vcxproj.filters
@@ -742,6 +742,9 @@
meta\Source Files
+
+ meta\Source Files
+
meta\Source Files
@@ -1165,6 +1168,9 @@
layout\Source Files
+
+ layout\Source Files
+
layout\Source Files
diff --git a/src/meta/hca_keys.h b/src/meta/hca_keys.h
index e8aa7520..35b2e029 100644
--- a/src/meta/hca_keys.h
+++ b/src/meta/hca_keys.h
@@ -4,8 +4,8 @@
#include "hca_keys_awb.h"
typedef struct {
- uint64_t key; /* hca key or seed key */
- const uint16_t *subkeys; /* derivation subkey table for seed key */
+ uint64_t key; /* hca key or seed ('user') key */
+ const uint16_t *subkeys; /* scramble subkey table for seed key */
size_t subkeys_size; /* size of the derivation subkey table */
} 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.
* 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).
* vgmstream derives the key if subkey table is provided.
*/
diff --git a/src/meta/meta.h b/src/meta/meta.h
index f8b805d5..08ce7489 100644
--- a/src/meta/meta.h
+++ b/src/meta/meta.h
@@ -799,4 +799,6 @@ VGMSTREAM * init_vgmstream_xwma(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_xopus(STREAMFILE * streamFile);
+VGMSTREAM * init_vgmstream_vs_ffx(STREAMFILE * streamFile);
+
#endif /*_META_H*/
diff --git a/src/meta/ps2_ads.c b/src/meta/ps2_ads.c
index a20aedc7..4b280dd5 100644
--- a/src/meta/ps2_ads.c
+++ b/src/meta/ps2_ads.c
@@ -150,10 +150,11 @@ VGMSTREAM * init_vgmstream_ps2_ads(STREAMFILE *streamFile) {
loop_start_sample = loop_start / 2 / channel_count;
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] */
+ /* offset is absolute from the "cavia stream format" container that adjusts ADS start */
loop_flag = 1;
- loop_start_offset = loop_start;
+ loop_start_offset = loop_start - 0x800;
ignore_silent_frame_cavia = 1;
}
else if (loop_start % 0x800 != 0 || loop_start == 0) { /* not sector aligned */
diff --git a/src/meta/riff.c b/src/meta/riff.c
index eb18e431..6da5f1b8 100644
--- a/src/meta/riff.c
+++ b/src/meta/riff.c
@@ -273,8 +273,9 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
* .adp: Headhunter (DC)
* .xss: Spider-Man The Movie (Xbox)
* .xsew: Mega Man X Legacy Collections (PC)
- * .adpcm: Angry Birds Transformers (Android) */
- if ( check_extensions(streamFile, "wav,lwav,xwav,da,dax,cd,med,snd,adx,adp,xss,xsew,adpcm") ) {
+ * .adpcm: Angry Birds Transformers (Android)
+ * .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") ) {
diff --git a/src/meta/vs_ffx.c b/src/meta/vs_ffx.c
new file mode 100644
index 00000000..a7e71e94
--- /dev/null
+++ b/src/meta/vs_ffx.c
@@ -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;
+}
diff --git a/src/meta/xopus.c b/src/meta/xopus.c
index 63790b40..8ef98813 100644
--- a/src/meta/xopus.c
+++ b/src/meta/xopus.c
@@ -2,7 +2,7 @@
#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 * vgmstream = NULL;
off_t start_offset;
@@ -17,24 +17,21 @@ VGMSTREAM * init_vgmstream_xopus(STREAMFILE *streamFile) {
if (read_32bitBE(0x00, streamFile) != 0x584F7075) /* "XOpu" */
goto fail;
- /* 0x04: always 1? 0x30? */
+ /* 0x04: always 0x01? */
channel_count = read_8bit(0x05, streamFile);
/* 0x06: always 0x30? */
- /* 0x08: always 0xc8? encoder delay? */
+ /* 0x08: always 0xc8? max allowed packet size? */
num_samples = read_32bitLE(0x0c, streamFile);
- /* 0x10: always 0x138? max packet size? */
- entries = read_32bitLE(0x14, streamFile); /* packet sizes */
- /* 0x18: data size */
+ skip = read_32bitLE(0x10, streamFile);
+ entries = read_32bitLE(0x14, streamFile);
+ data_size = read_32bitLE(0x18, streamFile);
/* 0x1c: unused */
/* 0x20+: packet sizes table */
-
sample_rate = 48000;
loop_flag = 0;
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 */
@@ -43,7 +40,7 @@ VGMSTREAM * init_vgmstream_xopus(STREAMFILE *streamFile) {
vgmstream->meta_type = meta_XOPUS;
vgmstream->sample_rate = sample_rate;
- vgmstream->num_samples = num_samples /*- skip*/;
+ vgmstream->num_samples = num_samples;
#ifdef VGM_USE_FFMPEG
{
diff --git a/src/vgmstream.c b/src/vgmstream.c
index 4a6b4676..9bda15d1 100644
--- a/src/vgmstream.c
+++ b/src/vgmstream.c
@@ -444,7 +444,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_ue4opus,
init_vgmstream_xwma,
init_vgmstream_xopus,
-
+ init_vgmstream_vs_ffx,
/* 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 */
@@ -1018,6 +1018,7 @@ void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstre
case layout_blocked_sthd:
case layout_blocked_h4m:
case layout_blocked_xa_aiff:
+ case layout_blocked_vs_ffx:
render_vgmstream_blocked(buffer,sample_count,vgmstream);
break;
case layout_aix:
diff --git a/src/vgmstream.h b/src/vgmstream.h
index 15bb12b0..3a1d2ec6 100644
--- a/src/vgmstream.h
+++ b/src/vgmstream.h
@@ -253,6 +253,7 @@ typedef enum {
layout_blocked_sthd, /* Dream Factory STHD */
layout_blocked_h4m, /* H4M video */
layout_blocked_xa_aiff, /* XA in AIFF files [Crusader: No Remorse (SAT), Road Rash (3DO)] */
+ layout_blocked_vs_ffx,
/* otherwise odd */
layout_aix, /* CRI AIX's wheels within wheels */
@@ -701,6 +702,7 @@ typedef enum {
meta_XWMA,
meta_VA3, /* DDR Supernova 2 AC */
meta_XOPUS,
+ meta_VS_FFX,
} meta_t;