Merge pull request #1431 from bnnm/asrs

- Add/fix some .srsa [Fate/Samurai Remnant (PC)]
- Add FSB key
This commit is contained in:
bnnm 2023-10-08 12:44:22 +02:00 committed by GitHub
commit 9073e90aaa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 70 additions and 9 deletions

View File

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

View File

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

View File

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

View 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");

View File

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

View File

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