Merge branch 'lwma-vs-ads' of https://github.com/bnnm/vgmstream into bnnm-lwma-vs-ads

This commit is contained in:
Christopher Snowhill 2018-10-21 16:51:42 -07:00
commit da6aabc3cd
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
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*

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 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

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) {
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) {

View File

@ -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"},
};

View File

@ -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;
}

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_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);

View File

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

View File

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

View File

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

View File

@ -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.
*/

View File

@ -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*/

View File

@ -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 */

View File

@ -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") ) {

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"
/* 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
{

View File

@ -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:

View File

@ -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;