Merge pull request #1468 from bnnm/ghs-xa-etc

- Fix some .gtd/ged [Gunslinger Stratos (AC)]
- xa: fix crash
- bik: cleanup
- Add HCA key
- Fix some .sm1 [Splinter Cell: Pandora Tomorrow (PS2)]
- Add .ogg NXOpus [Trouble Witches Origin (Switch)]
- cleanup
This commit is contained in:
bnnm 2024-01-05 20:31:34 +01:00 committed by GitHub
commit 5de0d05537
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 429 additions and 237 deletions

View File

@ -59,9 +59,13 @@ class App(object):
def start(self):
print("TXTP dumper start")
filenames = []
for filename in self.args.files:
filenames += glob.glob(filename)
if os.path.isfile(filename): #for files in paths with regex-like format
filenames += [filename]
else:
filenames += glob.glob(filename)
for filename in filenames:
path = self.args.output or '.'

View File

@ -24,7 +24,7 @@ class Cli(object):
" %(prog)s * -r -fss 1\n"
" - make .txtp for all files in any subdirs with at least 1 subsong\n"
" (ignores formats without subsongs)\n\n"
" %(prog)s bgm.fsb -in -fcm 2 -fms 5.0\n"
" %(prog)s bgm.fsb -in -fcm 2 -fsm 5.0\n"
" - make .txtp for subsongs with at least 2 channels and 5 seconds\n\n"
" %(prog)s *.scd -r -fd -l 2\n"
" - make .txtp for all .scd in subdirs, ignoring dupes, one .txtp per 2ch\n\n"
@ -53,6 +53,7 @@ class Cli(object):
"* may be inside <...> for conditional text\n"))
p.add_argument('-z', dest='zero_fill', help="Zero-fill subsong number (default: auto per subsongs)", type=int)
p.add_argument('-ie', dest='no_internal_ext', help="Remove internal name's extension if any", action='store_true')
p.add_argument('-ip', dest='allow_internal_paths', help="Replace internal name's / paths with ~ (otherwise removed)", action='store_true')
p.add_argument('-m', dest='mini_txtp', help="Create mini-txtp", action='store_true')
p.add_argument('-s', dest='subsong_start', help="Start subsong", type=int)
p.add_argument('-S', dest='subsong_end', help="End subsong", type=int)
@ -270,13 +271,17 @@ class TxtpMaker(object):
return None
txt = self.info.stream_name
# remove paths #todo maybe config/replace?
pos = txt.rfind('\\')
if pos >= 0:
txt = txt[pos+1:]
pos = txt.rfind('/')
if pos >= 0:
txt = txt[pos+1:]
# remove paths
if self.cfg.allow_internal_paths:
txt = txt.replace("\\", "~")
txt = txt.replace("/", "~")
else:
pos = txt.rfind('\\')
if pos >= 0:
txt = txt[pos+1:]
pos = txt.rfind('/')
if pos >= 0:
txt = txt[pos+1:]
# remove bad chars
badchars = ['%', '*', '?', ':', '\"', '|', '<', '>']
@ -613,6 +618,7 @@ class App(object):
# subsongs should treat repeat names separately? pass flag?
#maker.reset(rename_map)
processing = False
while True:
try:
# main call to vgmstream
@ -623,10 +629,12 @@ class App(object):
# basic parse of vgmstream info
maker.parse(output_b)
processing = True
except (subprocess.CalledProcessError, ValueError) as e:
log.debug("ignoring CLI error in %s #%s: %s", filename_in, target_subsong, str(e))
errors += 1
break
if not processing: #stop but only if first subsong fails
break
if target_subsong == subsong_start:
log.debug("processing %s...", filename_in_clean)
@ -647,7 +655,7 @@ class App(object):
target_subsong += 1
if target_subsong % 200 == 0:
log.info("%s/%s subsongs... (%s dupes, %s errors)", target_subsong, maker.info.stream_count, dupes, errors)
log.info("%s/%s subsongs... (%s done, %s dupes, %s errors)", target_subsong, maker.info.stream_count, created, dupes, errors)
if os.path.exists(filename_out):
os.remove(filename_out)

View File

@ -500,10 +500,6 @@ different internally (encrypted, different versions, etc) and not always can be
- Krome .MUS header [*MUS_KROME*]
- *mus_krome*: `.mus`
- Codecs: NGC_DSP
- **dc_asd.c**
- ASD Header [*DC_ASD*]
- *dc_asd*: `.asd`
- Codecs: PCM16LE
- **spsd.c**
- Sega Naomi SPSD header [*SPSD*]
- *spsd*: `.str .spsd`
@ -1008,7 +1004,7 @@ different internally (encrypted, different versions, etc) and not always can be
- Codecs: FFmpeg(various)
- **bik.c**
- RAD Game Tools Bink header [*BINK*]
- *bik*: `.bik .bik2 .bk2 .ps3 .xmv .xen .vid .bika`
- *bik*: `.bik .bk2 .bik2 .ps3 .xmv .xen .vid .bika`
- Codecs: FFmpeg(various)
- **astb.c**
- Capcom ASTB header [*ASTB*]
@ -1049,7 +1045,9 @@ different internally (encrypted, different versions, etc) and not always can be
- *ghs*: `.gtd`
- *s_p_sth*: `.gtd`
- Subfiles: *msf*
- Codecs: XMA ATRAC9
- *s_pack*: `.ged`
- Subfiles: *ghs*
- Codecs: PCM16LE MSADPCM XMA ATRAC9
- **aac_triace.c**
- tri-Ace AAC header [*AAC_TRIACE*]
- *aac_triace*: `.aac .laac`
@ -1098,7 +1096,7 @@ different internally (encrypted, different versions, etc) and not always can be
- Codecs: PCM16BE PCM16LE AWC_IMA XMA2 MPEG VORBIS_custom ATRAC9 NGC_DSP
- **opus.c**
- Nintendo Switch OPUS header [*OPUS*]
- *opus_std*: `.opus .lopus .bgm .opu + .psi`
- *opus_std*: `.opus .lopus .bgm .opu .ogg .logg + .psi`
- *opus_n1*: `.opus .lopus`
- *opus_capcom*: `.opus .lopus`
- *opus_nop*: `.nop`
@ -1852,6 +1850,10 @@ different internally (encrypted, different versions, etc) and not always can be
- Rockstar .ivaud header [*IVAUD*]
- *ivaud*: `.ivaud .(extensionless)`
- Codecs: PCM16LE XMA1 MPEG IMA_int
- **asd_naxat.c**
- Naxat .ASD header [*ASD_NAXAT*]
- *asd_naxat*: `.asd`
- Codecs: PCM16LE
- **pos.c**
- RIFF WAVE header (.pos looping) [*RIFF_WAVE_POS*]
- *pos*: `.pos + .wav`
@ -1932,7 +1934,7 @@ different internally (encrypted, different versions, etc) and not always can be
- Codecs: FFmpeg(various)
- **ea_eaac.c**
- Electronic Arts SPS header [*EA_SPS*]
- *eaaudiocore_header*: `(base) + .sns`
- *eaaudiocore_main*: `(base) + .sns`
- Codecs: PCM16_int EA_XAS_V1 MPEG NGC_DSP SPEEX ATRAC9 Opus XMA1 XMA2
## Supported extras

View File

@ -204,6 +204,7 @@ static const char* extension_list[] = {
"gcm",
"gcub",
"gcw",
"ged",
"genh",
"gin",
"gmd", //txth/semi [High Voltage games: Charlie and the Chocolate Factory (GC), Zathura (GC)]
@ -366,6 +367,7 @@ static const char* extension_list[] = {
"msvp", //fake extension/header id for .msv
"mta2",
"mtaf",
"mtt", //txth/reserved [Splinter Cell: Pandora Tomorrow (PS2)]
"mul",
"mups",
"mus",
@ -1101,7 +1103,7 @@ static const meta_info meta_info_list[] = {
{meta_MUS_KROME, "Krome .MUS header"},
{meta_WII_SNG, "SNG DSP Header"},
{meta_RSD, "Radical RSD header"},
{meta_DC_ASD, "ASD Header"},
{meta_ASD_NAXAT, "Naxat .ASD header"},
{meta_SPSD, "Sega Naomi SPSD header"},
{meta_FFXI_BGW, "Square Enix .BGW header"},
{meta_FFXI_SPW, "Square Enix .SPW header"},

View File

@ -361,6 +361,7 @@
<ClCompile Include="meta\ao.c" />
<ClCompile Include="meta\apc.c" />
<ClCompile Include="meta\apple_caff.c" />
<ClCompile Include="meta\asd_naxat.c" />
<ClCompile Include="meta\asf.c" />
<ClCompile Include="meta\ast.c" />
<ClCompile Include="meta\astb.c" />
@ -402,7 +403,6 @@
<ClCompile Include="meta\cstr.c" />
<ClCompile Include="meta\cxs.c" />
<ClCompile Include="meta\dcs_wav.c" />
<ClCompile Include="meta\dc_asd.c" />
<ClCompile Include="meta\dc_idvi.c" />
<ClCompile Include="meta\dc_kcey.c" />
<ClCompile Include="meta\deblock_streamfile.c" />

View File

@ -904,6 +904,9 @@
<ClCompile Include="meta\apple_caff.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\asd_naxat.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\asf.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
@ -1027,9 +1030,6 @@
<ClCompile Include="meta\dcs_wav.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\dc_asd.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\dc_idvi.c">
<Filter>meta\Source Files</Filter>
</ClCompile>

61
src/meta/asd_naxat.c Normal file
View File

@ -0,0 +1,61 @@
#include "meta.h"
#include "../coding/coding.h"
/* ASD - found Naxat (Spiel/Mesa) games [Miss Moonlight (DC), Yoshia no Oka de Nekoronde... (DC)] */
VGMSTREAM* init_vgmstream_asd_naxat(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
uint32_t start_offset;
int loop_flag, channels, sample_rate;
/* checks */
uint32_t data_size = read_u32le(0x00, sf); /* padded and slightly less than file size */
if (data_size == 0 || data_size >= get_streamfile_size(sf) || data_size + 0x20 + 0x10 < get_streamfile_size(sf))
return NULL;
if (data_size != read_u32le(0x04,sf)) /* repeated size */
return NULL;
/* extension of the audio bigfiles (there are N offsets to these subfiles) */
if (!check_extensions(sf, "asd"))
return NULL;
/* fmt chunk, extra checks since format is simple */
if (read_u16le(0x08,sf) != 0x01) /* format*/
return NULL;
channels = read_u16le(0x0a,sf);
sample_rate = read_s32le(0x0c,sf);
if (channels < 1 || channels > 2)
return NULL;
if (sample_rate != 22050)
return NULL;
if (sample_rate * channels * sizeof(int16_t) != read_u32le(0x10,sf)) /* bitrate */
return NULL;
/* 04: block size, bps */
if (read_u32le(0x18,sf) != 0x00 )
return NULL;
if (read_u32le(0x1c,sf) != 0x00 )
return NULL;
start_offset = 0x20;
loop_flag = 0;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_ASD_NAXAT;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = pcm16_bytes_to_samples(data_size, channels);
vgmstream->coding_type = coding_PCM16LE;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x02;
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -2,7 +2,7 @@
#include "../coding/coding.h"
#include "../util.h"
static int bink_get_info(STREAMFILE* sf, int target_subsong, int* p_total_subsongs, size_t* p_stream_size, int* p_channels, int* p_sample_rate, int* p_num_samples);
static bool bink_get_info(STREAMFILE* sf, int target_subsong, int* p_total_subsongs, size_t* p_stream_size, int* p_channels, int* p_sample_rate, int* p_num_samples);
/* BINK 1/2 - RAD Game Tools movies (audio/video format) */
VGMSTREAM* init_vgmstream_bik(STREAMFILE* sf) {
@ -17,13 +17,14 @@ VGMSTREAM* init_vgmstream_bik(STREAMFILE* sf) {
(read_u32be(0x00,sf) & 0xffffff00) != get_id32be("KB2\0"))
goto fail;
/* .bik/bik2/bk2: standard
/* .bik/bk2: standard
* .bik2: older?
* .xmv: Reflections games [Driver: Parallel Lines (Wii), Emergency Heroes (Wii)]
* .bik.ps3: Neversoft games [Guitar Hero: Warriors of Rock (PS3)]
* .bik.xen: Neversoft games [various Guitar Hero (PC/PS3/X360)]
* .vid: Etrange Libellules games [Alice in Wonderland (PC)]
* .bika: fake extension for demuxed audio */
if (!check_extensions(sf,"bik,bik2,bk2,ps3,xmv,xen,vid,bika"))
if (!check_extensions(sf,"bik,bk2,bik2,ps3,xmv,xen,vid,bika"))
goto fail;
/* find target stream info and samples */
@ -59,79 +60,126 @@ fail:
return NULL;
}
/* official values */
#define BINK_MAX_FRAMES 1000000
#define BINK_MAX_TRACKS 256
/**
* Gets stream info, and number of samples in a BINK file by reading all frames' headers (as it's VBR),
* as they are not in the main header. The header for BINK1 and 2 is the same.
* (a ~3 min movie needs ~6000-7000 frames = fseeks, should be fast enough)
*/
static int bink_get_info(STREAMFILE* sf, int target_subsong, int* p_total_subsongs, size_t* p_stream_size, int* p_channels, int* p_sample_rate, int* p_num_samples) {
uint32_t* offsets = NULL;
uint32_t num_frames, num_samples_b = 0;
* see: https://wiki.multimedia.cx/index.php?title=Bink_Container */
static bool bink_get_info(STREAMFILE* sf, int target_subsong, int* p_total_subsongs, size_t* p_stream_size, int* p_channels, int* p_sample_rate, int* p_num_samples) {
uint32_t* offsets = NULL; //TODO rename
uint32_t num_samples_b = 0;
off_t cur_offset;
int i, j, sample_rate, channels;
int total_subsongs;
size_t stream_size = 0;
size_t filesize = get_streamfile_size(sf);
uint32_t signature = (read_32bitBE(0x00,sf) & 0xffffff00);
uint8_t revision = (read_32bitBE(0x00,sf) & 0xFF);
/* known revisions:
* bik1: b,d,f,g,h,i,k [no "j"]
* bik2: a,d,f,g,h,i,j,k,m,n [no "l"]
* (current public binkplay.exe allows 1=f~k and 2=f~n) */
uint32_t head_id = read_u32be(0x00,sf);
uint32_t file_size = read_u32le(0x04,sf) + 0x08;
uint32_t num_frames = read_u32le(0x08,sf);
/* 0x0c: largest frame */
/* 0x10: num_frames again (found even for files without audio) */
/* 0x14: video width (max 32767, apparently can be negative but no different meaning) */
/* 0x18: video height (max 32767) */
/* 0x1c: fps dividend (must be set) */
/* 0x20: fps divider (must be set)
* - ex. 2997/100 = 29.97 fps, 30/1 = 30 fps (common values) */
//uint32_t video_flags = read_u32le(0x24,sf); /* (scale, alpha, color modes, etc) */
/* 0x28: audio tracks */
/* video flags:
- F0000000 (bits 28-31): width and height scaling bits (doubled, interlaced, etc)
- 00100000 (bit 20): has alpha plane
- 00040000 (bit 18): unknown, related to packet format? (seen in some bik2 n+, with and w/o audio)
- 00020000 (bit 17): grayscale
- 00010000 (bit 16): 12 16b numbers? (seen in binkplay)
- 00000010 (bit 4): 1 big number? (seems always set in bik1 k+ bik2 i+, but also set in bik2 g wihtout the number)
- 00000004 (bit 2): 6 16b (seen in some bik2 n+)
- 00000002 (bit 1): unknown (seen in some bik2 n+, with and w/o audio)
(from binkplay, flags 0x04 and 0x10000 can't coexist)
*/
if (file_size != get_streamfile_size(sf))
return false;
if (num_frames <= 0 || num_frames > BINK_MAX_FRAMES)
return false; /* (avoids big allocs below) */
if (read_32bitLE(0x04,sf) + 0x08 != filesize)
goto fail;
num_frames = (uint32_t)read_32bitLE(0x08,sf);
if (num_frames == 0 || num_frames > 0x100000) goto fail; /* something must be off (avoids big allocs below) */
uint32_t signature = head_id & 0xffffff00;
uint8_t revision = head_id & 0xFF;
int sample_rate, channels;
uint16_t audio_flags;
/* multichannel/multilanguage audio is usually N streams of stereo/mono, no way to know channel layout */
total_subsongs = read_32bitLE(0x28,sf);
int total_subsongs = read_s32le(0x28,sf);
if (total_subsongs < 1) {
vgm_logi("BIK: no audio in movie (ignore)\n");
goto fail;
}
if (target_subsong == 0) target_subsong = 1;
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs > 255) goto fail;
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs > BINK_MAX_TRACKS) goto fail;
/* find stream info and position in offset table */
cur_offset = 0x2c;
if ((signature == 0x42494B00 && (revision == 0x6b)) || /* k */
(signature == 0x4B423200 && (revision == 0x69 || revision == 0x6a || revision == 0x6b))) /* i,j,k */
cur_offset += 0x04; /* unknown v2 header field */
cur_offset += 0x04*total_subsongs; /* skip streams max packet bytes */
sample_rate = (uint16_t)read_16bitLE(cur_offset+0x04*(target_subsong-1)+0x00,sf);
channels = (uint16_t)read_16bitLE(cur_offset+0x04*(target_subsong-1)+0x02,sf) & 0x2000 ? 2 : 1; /* stereo flag */
cur_offset += 0x04*total_subsongs; /* skip streams info */
cur_offset += 0x04*total_subsongs; /* skip streams ids */
if ((signature == get_id32be("BIK\0") && revision >= 'k') || (signature == get_id32be("KB2\0") && revision >= 'i'))
cur_offset += 0x04;
//if (video_flags & 0x000004) /* only n+? */
// cur_offset += 0x0c; /* 6 number: s16 * 0.00003051850944757462 (video stuff?) */
//if (video_flags & 0x010000)
// cur_offset += 0x18;
//if (video_flags & 0x000010) /* only i+? */
// cur_offset += 0x04;
cur_offset += 0x04 * total_subsongs; /* skip streams max packet bytes */
sample_rate = read_u16le(cur_offset + 0x04 * (target_subsong - 1) + 0x00, sf);
audio_flags = read_u16le(cur_offset + 0x04 * (target_subsong - 1) + 0x02, sf);
cur_offset += 0x04 * total_subsongs; /* skip streams info */
cur_offset += 0x04 * total_subsongs; /* skip streams ids */
/* audio flags:
- 8000 (bit 15): unknown (observed in some samples)
- 4000 (bit 14): unknown (same file may have it set for none/some/all)
- 2000 (bit 13): stereo flag
- 1000 (bit 12): audio type (1=DCT, 0=FFT)
*/
channels = audio_flags & 0x2000 ? 2 : 1;
/* read frame offsets in a buffer, to avoid fseeking to the table back and forth */
offsets = malloc(sizeof(uint32_t) * num_frames);
offsets = malloc(num_frames * sizeof(uint32_t));
if (!offsets) goto fail;
for (i=0; i < num_frames; i++) {
offsets[i] = read_32bitLE(cur_offset,sf) & 0xFFFFFFFE; /* mask first bit (= keyframe) */
for (int i = 0; i < num_frames; i++) {
offsets[i] = read_u32le(cur_offset, sf) & 0xFFFFFFFE; /* mask first bit (= keyframe) */
cur_offset += 0x4;
if (offsets[i] > filesize) goto fail;
if (offsets[i] > file_size)
goto fail;
}
/* after the last index is the file size, validate just in case */
if (read_32bitLE(cur_offset,sf) != filesize) goto fail;
if (read_u32le(cur_offset,sf) != file_size)
goto fail;
/* read each frame header and sum all samples
* a frame has N audio packets with a header (one per stream) + video packet */
for (i=0; i < num_frames; i++) {
for (int i = 0; i < num_frames; i++) {
cur_offset = offsets[i];
/* read audio packet headers per stream */
for (j=0; j < total_subsongs; j++) {
uint32_t ap_size = read_32bitLE(cur_offset+0x00,sf); /* not counting this int */
for (int j = 0; j < total_subsongs; j++) {
uint32_t ap_size = read_u32le(cur_offset + 0x00,sf); /* not counting this int */
if (j == target_subsong-1) {
if (j + 1 == target_subsong) {
stream_size += 0x04 + ap_size;
if (ap_size > 0)
num_samples_b += read_32bitLE(cur_offset+0x04,sf); /* decoded samples in bytes */
num_samples_b += read_u32le(cur_offset + 0x04,sf); /* decoded samples in bytes */
break; /* next frame */
}
else { /* next stream packet or frame */
@ -140,8 +188,6 @@ static int bink_get_info(STREAMFILE* sf, int target_subsong, int* p_total_subson
}
}
free(offsets);
if (p_total_subsongs) *p_total_subsongs = total_subsongs;
if (p_stream_size) *p_stream_size = stream_size;
@ -150,9 +196,9 @@ static int bink_get_info(STREAMFILE* sf, int target_subsong, int* p_total_subson
//todo returns a few more samples (~48) than binkconv.exe?
if (p_num_samples) *p_num_samples = num_samples_b / (2 * channels);
return 1;
free(offsets);
return true;
fail:
free(offsets);
return 0;
return false;
}

View File

@ -1,84 +0,0 @@
#include "meta.h"
#include "../util.h"
/* ASD - found in Miss Moonlight (DC) */
VGMSTREAM * init_vgmstream_dc_asd(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t start_offset;
int loop_flag;
int channel_count;
int sample_rate;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("asd",filename_extension(filename))) goto fail;
/* We have no "Magic" words in this header format, so we have to do some,
other checks, it seems the samplecount is stored twice in the header,
we'll compare it... */
if (read_32bitLE(0x0,streamFile) != read_32bitLE(0x4,streamFile))
goto fail;
/* ableton related files can be incorrectly sent to this which don't have
the same style of header and unless we null check we get a divide by zero
crash... */
sample_rate = read_32bitLE(0xC,streamFile);
if (!sample_rate)
goto fail;
/* compare the frequency with the bitrate, if it doesn't match we'll close
the vgmstream... */
if (read_32bitLE(0x10,streamFile)/sample_rate != (uint16_t)read_16bitLE(0xA,streamFile)*2)
goto fail;
loop_flag = 0;
channel_count = read_16bitLE(0x0A,streamFile);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
start_offset = get_streamfile_size(streamFile) - read_32bitLE(0x0,streamFile);
vgmstream->channels = channel_count;
vgmstream->sample_rate = sample_rate;
vgmstream->coding_type = coding_PCM16LE;
vgmstream->num_samples = read_32bitLE(0x0,streamFile)/2/channel_count;
if (loop_flag) {
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = read_32bitLE(0x0,streamFile)/2/channel_count;
}
vgmstream->meta_type = meta_DC_ASD;
if (vgmstream->channels == 1) {
vgmstream->layout_type = layout_none;
} else if (vgmstream->channels == 2) {
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x2;
}
/* open the file for reading */
{
int i;
STREAMFILE * file;
file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!file) goto fail;
for (i=0;i<channel_count;i++) {
vgmstream->ch[i].streamfile = file;
vgmstream->ch[i].channel_start_offset=
vgmstream->ch[i].offset=start_offset+
vgmstream->interleave_block_size*i;
}
}
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}

View File

@ -1,96 +1,145 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../util/endianness.h"
typedef enum { XMA2, ATRAC9 } gtd_codec;
//TODO rename gtd to ghs
/* GHS - Hexadrive's HexaEngine games [Knights Contract (X360), Valhalla Knights 3 (Vita)] */
typedef enum { PCM16LE, MSADPCM, XMA2, ATRAC9 } gtd_codec_t;
static void read_name(VGMSTREAM* vgmstream, STREAMFILE* sf, uint32_t offset);
/* GHS - Hexadrive's HexaEngine games [Gunslinger Stratos (AC), Knights Contract (X360), Valhalla Knights 3 (Vita)] */
VGMSTREAM* init_vgmstream_ghs(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset, chunk_offset, stpr_offset, name_offset = 0, loop_start_offset, loop_end_offset;
size_t data_size, chunk_size;
uint32_t stream_offset, stream_size, stpr_offset = 0, loop_start_offset = 0, loop_end_offset = 0;
uint32_t chunk_offset, chunk_size = 0, at9_config_data = 0, block_size = 0;
int loop_flag, channels, sample_rate;
int num_samples, loop_start_sample, loop_end_sample;
uint32_t at9_config_data;
gtd_codec codec;
int32_t num_samples, loop_start_sample, loop_end_sample;
gtd_codec_t codec;
int total_subsongs = 0, target_subsong = sf->stream_index;
/* checks */
if (!is_id32be(0x00,sf, "GHS "))
goto fail;
if ( !check_extensions(sf,"gtd"))
return NULL;
if (!check_extensions(sf,"gtd"))
return NULL;
int big_endian = guess_endian32(0x04,sf);
read_u32_t read_u32 = big_endian ? read_u32be : read_u32le;
read_u16_t read_u16 = big_endian ? read_u16be : read_u16le;
int is_old = 0x34 + read_u32le(0x30,sf) + read_u32le(0x0c,sf) == get_streamfile_size(sf);
total_subsongs = read_u32(0x04, sf); /* seen in sfx packs inside .ged */
if (!check_subsongs(&target_subsong, total_subsongs))
return NULL;
/* not seen */
if (target_subsong > 1 && is_old)
goto fail;
/* header type, not formally specified */
if (read_32bitBE(0x04,sf) == 1 && read_16bitBE(0x0C,sf) == 0x0166) { /* XMA2 */
/* 0x08(4): seek table size */
chunk_offset = 0x0c; /* custom header with a "fmt " data chunk inside */
chunk_size = 0x34;
channels = read_16bitBE(chunk_offset+0x02,sf);
sample_rate = read_32bitBE(chunk_offset+0x04,sf);
xma2_parse_fmt_chunk_extra(sf, chunk_offset, &loop_flag, &num_samples, &loop_start_sample, &loop_end_sample, 1);
start_offset = read_32bitBE(0x58,sf); /* always 0x800 */
data_size = read_32bitBE(0x5c,sf);
/* 0x34(18): null, 0x54(4): seek table offset, 0x58(4): seek table size, 0x5c(8): null, 0x64: seek table */
stpr_offset = read_32bitBE(chunk_offset+0x54,sf) + read_32bitBE(chunk_offset+0x58,sf);
if (is_id32be(stpr_offset,sf, "STPR")) {
/* SRPR encases the original "S_P_STH" header (no data) */
name_offset = stpr_offset + 0xB8; /* there are offsets fields but seems to work */
/* header version, not formally specified */
if (!is_old) {
/* 0x08: size of all seek tables (XMA2, all tables go together after headers) / null */
uint32_t offset = 0x0c + (target_subsong - 1) * 0x64;
int format = read_u16(offset + 0x00,sf);
if (format == 0x0001)
codec = PCM16LE; /* GS bgm */
else if (format == 0x0002)
codec = MSADPCM; /* GS sfx */
else if (format == 0x0166) {
codec = XMA2;
chunk_offset = offset; /* "fmt " */
chunk_size = 0x34;
}
else {
goto fail;
}
codec = XMA2;
}
else if (0x34 + read_32bitLE(0x30,sf) + read_32bitLE(0x0c,sf) == get_streamfile_size(sf)) { /* ATRAC9 */
/* 0x0c: standard fmt chunk (depending on format, reserved with padding up to 0x48 if needed) */
channels = read_u16(offset + 0x02,sf);
sample_rate = read_u32(offset + 0x04,sf);
block_size = read_u16(offset + 0x0c,sf);
/* loops can be found at 0x28/2c in PCM16 (also later) */
stream_offset = read_u32(offset + 0x4c,sf); /* always 0x800 */
stream_size = read_u32(offset + 0x50,sf);
/* 0x54: seek table offset (XMA2) / data start */
/* 0x58: seek table size (XMA2) / null */
loop_start_sample = read_u32(offset + 0x5c,sf); /* null in XMA2 */
loop_end_sample = read_u32(offset + 0x60,sf) + loop_start_sample; /* +1? */
data_size = read_32bitLE(0x0c,sf);
start_offset = 0x34 + read_32bitLE(0x30,sf);
channels = read_32bitLE(0x10,sf);
sample_rate = read_32bitLE(0x14,sf);
loop_start_offset = read_32bitLE(0x1c, sf);
loop_end_offset = read_32bitLE(0x20, sf);
loop_flag = loop_end_offset > loop_start_offset;
at9_config_data = read_32bitBE(0x28,sf);
/* 0x18-0x28: fixed/unknown values */
stpr_offset = 0x2c;
if (is_id32be(stpr_offset,sf, "STPR")) {
/* STPR encases the original "S_P_STH" header (no data) */
name_offset = stpr_offset + 0xE8; /* there are offsets fields but seems to work */
if (codec == XMA2) {
xma2_parse_fmt_chunk_extra(sf, chunk_offset, &loop_flag, &num_samples, &loop_start_sample, &loop_end_sample, 1);
}
else {
loop_flag = loop_end_sample != 0;
}
codec = ATRAC9;
stpr_offset = read_u32(offset + 0x54,sf) + read_u32(offset + 0x58,sf);
}
else {
goto fail;
}
codec = ATRAC9;
/* 08: always 02? */
stream_size = read_u32(0x0c,sf);
channels = read_u32(0x10,sf);
sample_rate = read_u32(0x14,sf);
/* 18: null? */
loop_start_offset = read_u32(0x1c,sf);
loop_end_offset = read_u32(0x20,sf);
/* 24: channel layout? */
at9_config_data = read_u32be(0x28,sf);
/* 2c: STPR */
stream_offset = read_u32(0x30,sf) + 0x34;
loop_flag = loop_end_offset > loop_start_offset;
stpr_offset = 0x2c;
}
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_GHS;
vgmstream->sample_rate = sample_rate;
vgmstream->loop_start_sample = loop_start_sample;
vgmstream->loop_end_sample = loop_end_sample;
vgmstream->meta_type = meta_GHS;
if (name_offset) //encoding is Shift-Jis in some PSV files
read_string(vgmstream->stream_name,STREAM_NAME_SIZE, name_offset,sf);
vgmstream->loop_end_sample = loop_end_sample;
vgmstream->num_streams = total_subsongs;
vgmstream->stream_size = stream_size;
read_name(vgmstream, sf, stpr_offset);
switch(codec) {
case PCM16LE:
vgmstream->coding_type = coding_PCM16LE;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = block_size / channels;
vgmstream->num_samples = pcm16_bytes_to_samples(stream_size, channels);
break;
case MSADPCM:
vgmstream->coding_type = coding_MSADPCM;
vgmstream->layout_type = layout_interleave;
vgmstream->frame_size = block_size;
vgmstream->num_samples = msadpcm_bytes_to_samples(stream_size, block_size, channels);
break;
#ifdef VGM_USE_FFMPEG
case XMA2:
vgmstream->codec_data = init_ffmpeg_xma_chunk(sf, start_offset, data_size, chunk_offset, chunk_size);
vgmstream->codec_data = init_ffmpeg_xma_chunk(sf, stream_offset, stream_size, chunk_offset, chunk_size);
if ( !vgmstream->codec_data ) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
vgmstream->num_samples = num_samples;
xma_fix_raw_samples(vgmstream, sf, start_offset, data_size, chunk_offset, 1,1);
xma_fix_raw_samples(vgmstream, sf, stream_offset, stream_size, chunk_offset, 1,1);
break;
#endif
#ifdef VGM_USE_ATRAC9
@ -105,13 +154,12 @@ VGMSTREAM* init_vgmstream_ghs(STREAMFILE* sf) {
vgmstream->coding_type = coding_ATRAC9;
vgmstream->layout_type = layout_none;
if (loop_flag) {
vgmstream->loop_start_sample = atrac9_bytes_to_samples(loop_start_offset - start_offset, vgmstream->codec_data);
vgmstream->loop_end_sample = atrac9_bytes_to_samples(loop_end_offset - start_offset, vgmstream->codec_data);
vgmstream->loop_start_sample = atrac9_bytes_to_samples(loop_start_offset - stream_offset, vgmstream->codec_data);
vgmstream->loop_end_sample = atrac9_bytes_to_samples(loop_end_offset - stream_offset, vgmstream->codec_data);
}
vgmstream->num_samples = atrac9_bytes_to_samples(data_size, vgmstream->codec_data);
vgmstream->num_samples = atrac9_bytes_to_samples(stream_size, vgmstream->codec_data);
break;
}
#endif
default:
@ -119,7 +167,7 @@ VGMSTREAM* init_vgmstream_ghs(STREAMFILE* sf) {
}
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
if (!vgmstream_open_stream(vgmstream, sf, stream_offset))
goto fail;
return vgmstream;
fail:
@ -131,14 +179,14 @@ fail:
VGMSTREAM* init_vgmstream_s_p_sth(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
STREAMFILE* temp_sf = NULL;
uint32_t subfile_offset, subfile_size, name_offset;
uint32_t subfile_offset, subfile_size, stpr_offset;
/* checks */
if (!is_id64be(0x00,sf,"S_P_STH\x01"))
goto fail;
return NULL;
if (!check_extensions(sf,"gtd"))
goto fail;
return NULL;
subfile_offset = read_u32be(0x08, sf);
subfile_size = get_streamfile_size(sf) - subfile_offset;
@ -150,8 +198,52 @@ VGMSTREAM* init_vgmstream_s_p_sth(STREAMFILE* sf) {
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_GHS;
name_offset = 0xB0; /* there are offsets fields but seems to work */
read_string(vgmstream->stream_name, STREAM_NAME_SIZE, name_offset, sf);
stpr_offset = 0x00;
read_name(vgmstream, sf, stpr_offset);
close_streamfile(temp_sf);
return vgmstream;
fail:
close_streamfile(temp_sf);
close_vgmstream(vgmstream);
return NULL;
}
/* S_PACK - Hexadrive's HexaEngine games [Gunslinger Stratos (PC), Knights Contract (X360)] */
VGMSTREAM* init_vgmstream_s_pack(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
STREAMFILE* temp_sf = NULL;
/* checks */
if (!is_id64be(0x00,sf,"S_PACK\x00\x00") && !is_id64be(0x00,sf,"S_PACK\x00\x01")) /* v1: KC */
return NULL;
if (!check_extensions(sf,"ged"))
return NULL;
/* 0x08: file size */
/* 0x0c-0x20: null */
int big_endian = guess_endian32(0x20,sf);
read_u32_t read_u32 = big_endian ? read_u32be : read_u32le;
uint32_t offset = read_u32(0x20, sf); /* offset to minitable */
/* 0x24: number of chunks in S_P_H? */
/* 0x28: number of entries in minitable */
/* minitable */
/* 0x00: offset to "S_P_H", that seems to have cuenames (may have more cues than waves though) */
uint32_t subfile_offset = read_u32(offset + 0x04, sf); /* may be null or S_CHR_M (no GHS in file) */
uint32_t schar_offset = read_u32(offset + 0x08, sf); /* S_CHR_M seen in KC, some kind of cues */
if (schar_offset == 0)
schar_offset = get_streamfile_size(sf);
uint32_t subfile_size = schar_offset - subfile_offset;
temp_sf = setup_subfile_streamfile(sf, subfile_offset, subfile_size, "gtd");
if (!temp_sf) goto fail;
vgmstream = init_vgmstream_ghs(temp_sf);
if (!vgmstream) goto fail;
close_streamfile(temp_sf);
return vgmstream;
@ -161,3 +253,41 @@ fail:
close_vgmstream(vgmstream);
return NULL;
}
static void read_name(VGMSTREAM* vgmstream, STREAMFILE* sf, uint32_t offset) {
uint32_t name_offset = 0;
//if (!offset) //may be 0 in PS3
// return;
if (is_id32be(offset,sf, "STPR"))
offset += 0x08;
if (is_id64be(offset + 0x00,sf, "S_P_STH\0")) { /* stream header v0: GS, VK3 */
/* 08 subheader size */
/* 0c version/count? */
/* 10 version/count? */
/* 20 offset to header configs */
/* 24 hash? */
/* 2c -1? */
/* 30 1? */
if (!is_id64be(offset + 0x40,sf, "stream\0\0"))
return;
/* 50 bank name */
/* 70+ header configs (some are repeats from GHS) */
/* E0 file name .gtd */
name_offset = offset + 0xE0; /* show file name though actual files are already (bankname)_(filename).gtd */
}
else if (is_id64be(offset + 0x00,sf, "S_P_STH\1")) { /* stream header v1: KC */
/* same as above, except no stream+bank name, so at 0x40 are header configs */
name_offset = offset + 0xB0;
}
/* optional (only found in streams, sfx packs that point to GHS have cue names) */
if (!name_offset)
return;
//TO-DO: Shift-Jis in some Vita files
read_string(vgmstream->stream_name,STREAM_NAME_SIZE, name_offset,sf);
}

View File

@ -1275,6 +1275,9 @@ static const hcakey_info hcakey_list[] = {
// Girls' Frontline 2: Exilium (PC)
{7152097263845921}, // 001968CB68CF8221
// Girls' Frontline 2: Exilium (PC)
{4079616028775461768}, // 389DB529D726B388
};
#endif/*_HCA_KEYS_H_*/

View File

@ -300,7 +300,7 @@ VGMSTREAM* init_vgmstream_mus_krome(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_rsd(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_dc_asd(STREAMFILE * streamFile);
VGMSTREAM* init_vgmstream_asd_naxat(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_spsd(STREAMFILE* sf);
@ -580,6 +580,7 @@ VGMSTREAM * init_vgmstream_mc3(STREAMFILE *streamFile);
VGMSTREAM* init_vgmstream_ghs(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_s_p_sth(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_s_pack(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_aac_triace(STREAMFILE* sf);

View File

@ -48,6 +48,9 @@ static int read_dsp_header_endian(struct dsp_header *header, off_t offset, STREA
header->sample_count = get_u32(buf+0x00);
if (header->sample_count > 0x10000000)
goto fail; /* unlikely to be that big, should catch fourccs */
/* usually nibbles = size*2 in mono, but interleaved stereo or L+R may use nibbles =~ size (or not), so can't
* easily reject files with more nibbles than data (nibbles may be part of the -R file) without redoing L+R handling */
header->nibble_count = get_u32(buf+0x04);
if (header->nibble_count > 0x10000000)
goto fail;

View File

@ -135,8 +135,9 @@ VGMSTREAM* init_vgmstream_opus_std(STREAMFILE* sf) {
/* .opus: standard / .lopus: for plugins
* .bgm: Cotton Reboot (Switch)
* .opu: Ys Memoire: The Oath in Felghana (Switch) */
if (!check_extensions(sf,"opus,lopus,bgm,opu"))
* .opu: Ys Memoire: The Oath in Felghana (Switch)
* .ogg: Trouble Witches Origin (Switch) */
if (!check_extensions(sf,"opus,lopus,bgm,opu,ogg,logg"))
goto fail;
offset = 0x00;

View File

@ -1818,6 +1818,7 @@ static int parse_type_audio(ubi_sb_header* sb, off_t offset, STREAMFILE* sf) {
sb->sample_rate = read_32bit(offset + sb->cfg.audio_sample_rate, sf);
sb->stream_type = read_32bit(offset + sb->cfg.audio_stream_type, sf);
//TO-DO a handful of SC:PT PS2 streams have 0 stream offset+size, maybe should set config + allow as dummies (ex. MAPS.SM1 #14191 #14255)
if (sb->stream_size == 0) {
VGM_LOG("UBI SB: bad stream size\n");
goto fail;
@ -2414,7 +2415,8 @@ static int parse_offsets(ubi_sb_header* sb, STREAMFILE* sf) {
break;
}
if (sb->stream_offset == 0) {
/* valid in rare cases with ram-streamed but also external file (SC:PT PS2 > MAPS.RS1)*/
if (sb->stream_offset == 0 && !sb->is_external) {
VGM_LOG("UBI SM: Failed to find offset for resource %d in subblock %d in map %s\n", sb->header_index, sb->subblock_id, sb->map_name);
goto fail;
}

View File

@ -30,7 +30,7 @@ VGMSTREAM* init_vgmstream_xa(STREAMFILE* sf) {
}
else {
/* non-blocked (ISO 2048 mode1/data) or incorrectly ripped: use TXTH */
goto fail;
return NULL;
}
/* .xa: common
@ -41,7 +41,7 @@ VGMSTREAM* init_vgmstream_xa(STREAMFILE* sf) {
* .xai: Quake II (PS1)
* (extensionless): bigfiles [Castlevania: Symphony of the Night (PS1)] */
if (!check_extensions(sf,"xa,str,pxa,grn,an2,,xai"))
goto fail;
return NULL;
/* Proper XA comes in raw (BIN 2352 mode2/form2) CD sectors, that contain XA subheaders.
* For headerless XA (ISO 2048 mode1/data) mode use TXTH. */
@ -138,15 +138,16 @@ fail:
static int xa_check_format(STREAMFILE *sf, off_t offset, int is_blocked) {
uint8_t frame_hdr[0x10];
int i, j, sector = 0, skip = 0;
off_t test_offset = offset;
const size_t sector_size = (is_blocked ? 0x900 : 0x800);
const size_t extra_size = (is_blocked ? 0x18 : 0x00);
const size_t frame_size = 0x80;
const int sector_max = 3;
const int skip_max = 32; /* videos interleave 7 or 15 sectors + 1 audio sector, maybe 31 too */
uint8_t frame_hdr[0x10];
int sector = 0, skip = 0;
uint32_t test_offset = offset;
/* test frames inside CD sectors */
while (sector < sector_max) {
if (is_blocked) {
@ -164,11 +165,11 @@ static int xa_check_format(STREAMFILE *sf, off_t offset, int is_blocked) {
test_offset += extra_size; /* header */
for (i = 0; i < (sector_size / frame_size); i++) {
for (int i = 0; i < (sector_size / frame_size); i++) {
read_streamfile(frame_hdr, test_offset, sizeof(frame_hdr), sf);
/* XA frame checks: filter indexes should be 0..3, and shifts 0..C */
for (j = 0; j < 16; j++) {
for (int j = 0; j < 16; j++) {
uint8_t header = get_u8(frame_hdr + j);
if (((header >> 4) & 0xF) > 0x03)
goto fail;
@ -180,11 +181,10 @@ static int xa_check_format(STREAMFILE *sf, off_t offset, int is_blocked) {
if (get_u32be(frame_hdr+0x00) != get_u32be(frame_hdr+0x04) ||
get_u32be(frame_hdr+0x08) != get_u32be(frame_hdr+0x0c))
goto fail;
/* blank frames should always use 0x0c0c0c0c due to how shift works, (in rare/unused file-channels it may be blank though) */
if (get_u32be(frame_hdr+0x00) == 0 &&
get_u32be(frame_hdr+0x04) == 0 &&
get_u32be(frame_hdr+0x08) == 0 &&
get_u32be(frame_hdr+0x0c) == 0)
/* blank frames should always use 0x0c0c0c0c due to how shift works, (in rare file-channels some frames may be blank though) */
if (i == 0 &&
get_u32be(frame_hdr+0x00) == 0 && get_u32be(frame_hdr+0x04) == 0 &&
get_u32be(frame_hdr+0x08) == 0 && get_u32be(frame_hdr+0x0c) == 0)
goto fail;
test_offset += 0x80;
@ -201,7 +201,7 @@ fail:
}
#define XA_MAX_CHANNELS 16
#define XA_MAX_CHANNELS 32 /* usually 08-16, seen ~24 in Langrisser V (PS1) */
typedef struct {
uint32_t info;
@ -270,9 +270,10 @@ static int xa_read_subsongs(STREAMFILE* sf, int target_subsong, uint32_t start,
if (xa_chan >= XA_MAX_CHANNELS) {
VGM_LOG("XA: too many channels: %x\n", xa_chan);
goto fail;
}
VGM_ASSERT((xa_submode & 0x01), "XA: end of audio at %x\n", offset); /* rare, signals last sector [Tetris (CD-i)] */
//;VGM_ASSERT((xa_submode & 0x01), "XA: end of audio at %x\n", offset); /* rare, signals last sector [Tetris (CD-i), Langrisser V (PS1)] */
//;VGM_ASSERT(is_eof, "XA: eof %02x%02x at %x\n", xa_file, xa_chan, offset); /* this sector still has data */
//;VGM_ASSERT(!is_audio, "XA: not audio at %x\n", offset);

View File

@ -51,3 +51,11 @@ size_t align_size_to_block(size_t value, size_t block_align) {
if (extra_size == 0) return value;
return (value + block_align - extra_size);
}
bool check_subsongs(int* target_subsong, int total_subsongs) {
if (*target_subsong == 0)
*target_subsong = 1;
if (*target_subsong < 0 || *target_subsong > total_subsongs || total_subsongs < 1)
return false;
return true;
}

View File

@ -53,4 +53,7 @@ void concatn(int length, char * dst, const char * src);
size_t align_size_to_block(size_t value, size_t block_align);
/* checks max subsongs and setups target */
bool check_subsongs(int* target_subsong, int total_subsongs);
#endif

View File

@ -127,7 +127,6 @@ init_vgmstream_t init_vgmstream_functions[] = {
init_vgmstream_ngc_pdt_split,
init_vgmstream_ngc_pdt,
init_vgmstream_mus_krome,
init_vgmstream_dc_asd,
init_vgmstream_spsd,
init_vgmstream_rsd,
init_vgmstream_bgw,
@ -524,6 +523,7 @@ init_vgmstream_t init_vgmstream_functions[] = {
init_vgmstream_adm2,
init_vgmstream_nxof,
init_vgmstream_gwb_gwd,
init_vgmstream_s_pack,
/* lower priority metas (no clean header identity, somewhat ambiguous, or need extension/companion file to identify) */
init_vgmstream_scd_pcm,
@ -535,6 +535,7 @@ init_vgmstream_t init_vgmstream_functions[] = {
init_vgmstream_seb,
init_vgmstream_tgc,
init_vgmstream_ivaud,
init_vgmstream_asd_naxat,
/* need companion files */
init_vgmstream_pos,
init_vgmstream_sli_loops,

View File

@ -370,11 +370,11 @@ typedef enum {
meta_FAG, /* Jackie Chan - Stuntmaster */
meta_PS2_MIHB, /* Merged MIH+MIB */
meta_NGC_PDT, /* Mario Party 6 */
meta_DC_ASD, /* Miss Moonligh */
meta_ASD_NAXAT,
meta_SPSD,
meta_RSD,
meta_PS2_ASS, /* ASS */
meta_SEG, /* Eragon */
meta_PS2_ASS,
meta_SEG,
meta_NDS_STRM_FFTA2, /* Final Fantasy Tactics A2 */
meta_KNON,
meta_ZWDSP, /* Zack and Wiki */