mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-18 07:44:43 +01:00
Merge branch 'bnnm-lwma-vs-ads'
This commit is contained in:
commit
5f842f7edd
90
README.md
90
README.md
@ -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*
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
@ -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"},
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
26
src/layout/blocked_vs_ffx.c
Normal file
26
src/layout/blocked_vs_ffx.c
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
@ -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"
|
||||||
>
|
>
|
||||||
|
@ -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" />
|
||||||
|
@ -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>
|
||||||
|
@ -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.
|
||||||
*/
|
*/
|
||||||
|
@ -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*/
|
||||||
|
@ -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 */
|
||||||
|
@ -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
53
src/meta/vs_ffx.c
Normal 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;
|
||||||
|
}
|
@ -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
|
||||||
{
|
{
|
||||||
|
@ -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:
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user