mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-28 08:20:54 +01:00
Merge pull request #1431 from bnnm/asrs
- Add/fix some .srsa [Fate/Samurai Remnant (PC)] - Add FSB key
This commit is contained in:
commit
9073e90aaa
4
.github/formats-info.py
vendored
4
.github/formats-info.py
vendored
@ -317,7 +317,7 @@ class App:
|
|||||||
with open(file, 'r', encoding='utf-8') as f:
|
with open(file, 'r', encoding='utf-8') as f:
|
||||||
is_updating = False
|
is_updating = False
|
||||||
for line in f:
|
for line in f:
|
||||||
line = line.strip()
|
line = line.strip('\n')
|
||||||
|
|
||||||
# find list section, add all current lines and ignore old ones until next section
|
# find list section, add all current lines and ignore old ones until next section
|
||||||
if line.startswith('### List'):
|
if line.startswith('### List'):
|
||||||
@ -334,6 +334,8 @@ class App:
|
|||||||
if not is_updating:
|
if not is_updating:
|
||||||
doc_lines.append(line)
|
doc_lines.append(line)
|
||||||
|
|
||||||
|
doc_lines.append('')
|
||||||
|
|
||||||
with open(file, 'w', encoding='utf-8', newline='\n') as f:
|
with open(file, 'w', encoding='utf-8', newline='\n') as f:
|
||||||
f.write('\n'.join(doc_lines))
|
f.write('\n'.join(doc_lines))
|
||||||
|
|
||||||
|
@ -523,6 +523,7 @@ static const char* extension_list[] = {
|
|||||||
"sps",
|
"sps",
|
||||||
"spsd",
|
"spsd",
|
||||||
"spw",
|
"spw",
|
||||||
|
"srsa",
|
||||||
"ss2",
|
"ss2",
|
||||||
"ssd", //txth/reserved [Zack & Wiki (Wii)]
|
"ssd", //txth/reserved [Zack & Wiki (Wii)]
|
||||||
"ssm",
|
"ssm",
|
||||||
|
@ -71,6 +71,7 @@ static const fsbkey_info fsbkey_list[] = {
|
|||||||
{ MODE_FSB5_STD, FSBKEY_ADD("Aurogon666") }, // Afterimage demo (PC)
|
{ MODE_FSB5_STD, FSBKEY_ADD("Aurogon666") }, // Afterimage demo (PC)
|
||||||
{ MODE_FSB5_STD, FSBKEY_ADD("IfYouLikeThosesSoundsWhyNotRenumerateTheir2Authors?") }, // Blanc (PC/Switch)
|
{ MODE_FSB5_STD, FSBKEY_ADD("IfYouLikeThosesSoundsWhyNotRenumerateTheir2Authors?") }, // Blanc (PC/Switch)
|
||||||
{ MODE_FSB5_STD, FSBKEY_ADD("L36nshM520") }, // Nishuihan Mobile (Android)
|
{ MODE_FSB5_STD, FSBKEY_ADD("L36nshM520") }, // Nishuihan Mobile (Android)
|
||||||
|
{ MODE_FSB5_STD, FSBKEY_ADD("Forza2!") }, // Forza Motorsport (PC)
|
||||||
|
|
||||||
/* these games use a key per file, seemingly generated from the filename; could be possible to add them but there is a lot of songs,
|
/* these games use a key per file, seemingly generated from the filename; could be possible to add them but there is a lot of songs,
|
||||||
so external .fsbkey may be better (use guessfsb 3.1 with --write-key-file) */
|
so external .fsbkey may be better (use guessfsb 3.1 with --write-key-file) */
|
||||||
|
@ -7,6 +7,7 @@ typedef enum { NONE, MSADPCM, DSP, GCADPCM, ATRAC9, RIFF_ATRAC9, KOVS, KTSS, } k
|
|||||||
#define MAX_CHANNELS 8
|
#define MAX_CHANNELS 8
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
bool is_srsa;
|
||||||
int total_subsongs;
|
int total_subsongs;
|
||||||
int target_subsong;
|
int target_subsong;
|
||||||
ktsr_codec codec;
|
ktsr_codec codec;
|
||||||
@ -31,12 +32,53 @@ typedef struct {
|
|||||||
char name[255+1];
|
char name[255+1];
|
||||||
} ktsr_header;
|
} ktsr_header;
|
||||||
|
|
||||||
|
static VGMSTREAM* init_vgmstream_ktsr_internal(STREAMFILE* sf, bool is_srsa);
|
||||||
static int parse_ktsr(ktsr_header* ktsr, STREAMFILE* sf);
|
static int parse_ktsr(ktsr_header* ktsr, STREAMFILE* sf);
|
||||||
static layered_layout_data* build_layered_atrac9(ktsr_header* ktsr, STREAMFILE *sf, uint32_t config_data);
|
static layered_layout_data* build_layered_atrac9(ktsr_header* ktsr, STREAMFILE *sf, uint32_t config_data);
|
||||||
static VGMSTREAM* init_vgmstream_ktsr_sub(STREAMFILE* sf_b, ktsr_header* ktsr, VGMSTREAM* (*init_vgmstream)(STREAMFILE* sf), const char* ext);
|
static VGMSTREAM* init_vgmstream_ktsr_sub(STREAMFILE* sf_b, ktsr_header* ktsr, VGMSTREAM* (*init_vgmstream)(STREAMFILE* sf), const char* ext);
|
||||||
|
|
||||||
/* KTSR - Koei Tecmo sound resource container */
|
/* KTSR - Koei Tecmo sound resource container */
|
||||||
VGMSTREAM* init_vgmstream_ktsr(STREAMFILE* sf) {
|
VGMSTREAM* init_vgmstream_ktsr(STREAMFILE* sf) {
|
||||||
|
return init_vgmstream_ktsr_internal(sf, false) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ASRS - container of KTSR found in newer games */
|
||||||
|
VGMSTREAM* init_vgmstream_asrs(STREAMFILE* sf) {
|
||||||
|
VGMSTREAM* vgmstream = NULL;
|
||||||
|
STREAMFILE* temp_sf = NULL;
|
||||||
|
|
||||||
|
/* checks */
|
||||||
|
if (!is_id32be(0x00, sf, "ASRS"))
|
||||||
|
return NULL;
|
||||||
|
/* 0x04: null */
|
||||||
|
/* 0x08: file size */
|
||||||
|
/* 0x0c: null */
|
||||||
|
|
||||||
|
/* .srsa: header id (as generated by common tools) */
|
||||||
|
if (!check_extensions(sf, "srsa"))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
|
||||||
|
/* mini-container of memory-KTSR (streams also have a "TSRS" for stream-KTSR).
|
||||||
|
* .srsa/srst usually have hashed filenames, so it isn't easy to match them, so this is mainly useful
|
||||||
|
* for .srsa with internal streams. */
|
||||||
|
uint32_t subfile_offset = 0x10;
|
||||||
|
uint32_t subfile_size = get_streamfile_size(sf) - subfile_offset;
|
||||||
|
|
||||||
|
/* use a subfile b/c it's a pain to change all the offsets below and it's also how engine would do it */
|
||||||
|
temp_sf = setup_subfile_streamfile(sf, subfile_offset,subfile_size, "ktsl2asbin");
|
||||||
|
if (!temp_sf) goto fail;
|
||||||
|
|
||||||
|
vgmstream = init_vgmstream_ktsr_internal(temp_sf, true);
|
||||||
|
close_streamfile(temp_sf);
|
||||||
|
return vgmstream;
|
||||||
|
fail:
|
||||||
|
close_streamfile(temp_sf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static VGMSTREAM* init_vgmstream_ktsr_internal(STREAMFILE* sf, bool is_srsa) {
|
||||||
VGMSTREAM* vgmstream = NULL;
|
VGMSTREAM* vgmstream = NULL;
|
||||||
STREAMFILE* sf_b = NULL;
|
STREAMFILE* sf_b = NULL;
|
||||||
ktsr_header ktsr = {0};
|
ktsr_header ktsr = {0};
|
||||||
@ -46,20 +88,22 @@ VGMSTREAM* init_vgmstream_ktsr(STREAMFILE* sf) {
|
|||||||
|
|
||||||
/* checks */
|
/* checks */
|
||||||
if (!is_id32be(0x00, sf, "KTSR"))
|
if (!is_id32be(0x00, sf, "KTSR"))
|
||||||
goto fail;
|
return NULL;
|
||||||
if (read_u32be(0x04, sf) != 0x777B481A) /* hash(?) id: 0x777B481A=as, 0x0294DDFC=st, 0xC638E69E=gc */
|
if (read_u32be(0x04, sf) != 0x777B481A) /* hash id: 0x777B481A=as, 0x0294DDFC=st, 0xC638E69E=gc */
|
||||||
goto fail;
|
return NULL;
|
||||||
|
|
||||||
/* .ktsl2asbin: common [Atelier Ryza (PC/Switch), Nioh (PC)]
|
/* .ktsl2asbin: common [Atelier Ryza (PC/Switch), Nioh (PC)]
|
||||||
* .asbin: Warriors Orochi 4 (PC) */
|
* .asbin: Warriors Orochi 4 (PC) */
|
||||||
if (!check_extensions(sf, "ktsl2asbin,asbin"))
|
if (!check_extensions(sf, "ktsl2asbin,asbin"))
|
||||||
goto fail;
|
return NULL;
|
||||||
|
|
||||||
/* KTSR can be a memory file (ktsl2asbin), streams (ktsl2stbin) and global config (ktsl2gcbin)
|
/* KTSR can be a memory file (ktsl2asbin), streams (ktsl2stbin) and global config (ktsl2gcbin)
|
||||||
* This accepts .ktsl2asbin with internal data or external streams as subsongs.
|
* This accepts .ktsl2asbin with internal data or external streams as subsongs.
|
||||||
* Some info from KTSR.bt */
|
* Hashes are meant to be read LE, but here are BE for easier comparison. Some info from KTSR.bt */
|
||||||
|
|
||||||
if (target_subsong == 0) target_subsong = 1;
|
if (target_subsong == 0) target_subsong = 1;
|
||||||
ktsr.target_subsong = target_subsong;
|
ktsr.target_subsong = target_subsong;
|
||||||
|
ktsr.is_srsa = is_srsa;
|
||||||
|
|
||||||
if (!parse_ktsr(&ktsr, sf))
|
if (!parse_ktsr(&ktsr, sf))
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -67,6 +111,9 @@ VGMSTREAM* init_vgmstream_ktsr(STREAMFILE* sf) {
|
|||||||
/* open companion body */
|
/* open companion body */
|
||||||
if (ktsr.is_external) {
|
if (ktsr.is_external) {
|
||||||
const char* companion_ext = check_extensions(sf, "asbin") ? "stbin" : "ktsl2stbin";
|
const char* companion_ext = check_extensions(sf, "asbin") ? "stbin" : "ktsl2stbin";
|
||||||
|
if (ktsr.is_srsa)
|
||||||
|
companion_ext = "srst";
|
||||||
|
|
||||||
sf_b = open_streamfile_by_ext(sf, companion_ext);
|
sf_b = open_streamfile_by_ext(sf, companion_ext);
|
||||||
if (!sf_b) {
|
if (!sf_b) {
|
||||||
vgm_logi("KTSR: companion file '*.%s' not found\n", companion_ext);
|
vgm_logi("KTSR: companion file '*.%s' not found\n", companion_ext);
|
||||||
@ -253,6 +300,7 @@ static int parse_codec(ktsr_header* ktsr) {
|
|||||||
/* platform + format to codec, simplified until more codec combos are found */
|
/* platform + format to codec, simplified until more codec combos are found */
|
||||||
switch(ktsr->platform) {
|
switch(ktsr->platform) {
|
||||||
case 0x01: /* PC */
|
case 0x01: /* PC */
|
||||||
|
case 0x05: /* PC/Steam [Fate/Samurai Remnant (PC)] */
|
||||||
if (ktsr->is_external) {
|
if (ktsr->is_external) {
|
||||||
if (ktsr->format == 0x0005)
|
if (ktsr->format == 0x0005)
|
||||||
ktsr->codec = KOVS; // Atelier Ryza (PC)
|
ktsr->codec = KOVS; // Atelier Ryza (PC)
|
||||||
@ -483,7 +531,7 @@ static int parse_ktsr(ktsr_header* ktsr, STREAMFILE* sf) {
|
|||||||
* 08: version?
|
* 08: version?
|
||||||
* 0a: unknown (usually 00, 02/03 seen in Vita)
|
* 0a: unknown (usually 00, 02/03 seen in Vita)
|
||||||
* 0b: platform (01=PC, 03=Vita, 04=Switch)
|
* 0b: platform (01=PC, 03=Vita, 04=Switch)
|
||||||
* 0c: game id?
|
* 0c: audio id? (seen in multiple files/games and used as Ogg stream IDs)
|
||||||
* 10: null
|
* 10: null
|
||||||
* 14: null
|
* 14: null
|
||||||
* 18: file size
|
* 18: file size
|
||||||
@ -506,8 +554,8 @@ static int parse_ktsr(ktsr_header* ktsr, STREAMFILE* sf) {
|
|||||||
|
|
||||||
/* parse chunk-like subfiles, usually N configs then N songs */
|
/* parse chunk-like subfiles, usually N configs then N songs */
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case 0x6172DBA8: /* padding (empty) */
|
case 0x6172DBA8: /* ? (mostly empty) */
|
||||||
case 0xBD888C36: /* config (floats, stream id, etc, may have extended name) */
|
case 0xBD888C36: /* cue? (floats, stream id, etc, may have extended name; can have sub-chunks)-appears N times */
|
||||||
case 0xC9C48EC1: /* unknown (has some string inside like "boss") */
|
case 0xC9C48EC1: /* unknown (has some string inside like "boss") */
|
||||||
case 0xA9D23BF1: /* "state container", some kind of config/floats, witgh names like 'State_bgm01'..N */
|
case 0xA9D23BF1: /* "state container", some kind of config/floats, witgh names like 'State_bgm01'..N */
|
||||||
case 0x836FBECA: /* unknown (~0x300, encrypted? table + data) */
|
case 0x836FBECA: /* unknown (~0x300, encrypted? table + data) */
|
||||||
@ -566,6 +614,13 @@ static int parse_ktsr(ktsr_header* ktsr, STREAMFILE* sf) {
|
|||||||
parse_longname(ktsr, sf, stream_id);
|
parse_longname(ktsr, sf, stream_id);
|
||||||
build_name(ktsr, sf);
|
build_name(ktsr, sf);
|
||||||
|
|
||||||
|
/* skip TSRS header */
|
||||||
|
if (ktsr->is_external && ktsr->is_srsa) {
|
||||||
|
for (int i = 0; i < ktsr->channels; i++) {
|
||||||
|
ktsr->stream_offsets[i] += 0x10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
fail:
|
fail:
|
||||||
vgm_logi("KTSR: unknown variation (report)\n");
|
vgm_logi("KTSR: unknown variation (report)\n");
|
||||||
|
@ -884,6 +884,7 @@ VGMSTREAM* init_vgmstream_diva(STREAMFILE* sf);
|
|||||||
VGMSTREAM* init_vgmstream_imuse(STREAMFILE* sf);
|
VGMSTREAM* init_vgmstream_imuse(STREAMFILE* sf);
|
||||||
|
|
||||||
VGMSTREAM* init_vgmstream_ktsr(STREAMFILE* sf);
|
VGMSTREAM* init_vgmstream_ktsr(STREAMFILE* sf);
|
||||||
|
VGMSTREAM* init_vgmstream_asrs(STREAMFILE* sf);
|
||||||
|
|
||||||
VGMSTREAM* init_vgmstream_mups(STREAMFILE* sf);
|
VGMSTREAM* init_vgmstream_mups(STREAMFILE* sf);
|
||||||
|
|
||||||
|
@ -458,6 +458,7 @@ init_vgmstream_t init_vgmstream_functions[] = {
|
|||||||
init_vgmstream_diva,
|
init_vgmstream_diva,
|
||||||
init_vgmstream_imuse,
|
init_vgmstream_imuse,
|
||||||
init_vgmstream_ktsr,
|
init_vgmstream_ktsr,
|
||||||
|
init_vgmstream_asrs,
|
||||||
init_vgmstream_mups,
|
init_vgmstream_mups,
|
||||||
init_vgmstream_kat,
|
init_vgmstream_kat,
|
||||||
init_vgmstream_pcm_success,
|
init_vgmstream_pcm_success,
|
||||||
|
Loading…
Reference in New Issue
Block a user