Merge pull request #1599 from bnnm/sead-etc

- Add .sab/mab XMA [Kingdom Hearts 3 (XONE)]
- Fix some looping .btsnd [Splatoon (WiiU)]
- Add FSB key
- Add .v RIFF extension
This commit is contained in:
bnnm 2024-09-16 00:24:10 +02:00 committed by GitHub
commit 1d836a3693
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 65 additions and 15 deletions

View File

@ -588,6 +588,7 @@ static const char* extension_list[] = {
"utk",
"uv",
"v",
"v0",
//"v1", //dual channel with v0
"va3",

View File

@ -10,24 +10,27 @@ VGMSTREAM* init_vgmstream_btsnd(STREAMFILE* sf) {
/* checks */
if (!check_extensions(sf, "btsnd"))
uint32_t type = read_u32be(0x00,sf);
if (type != 0x00 && type != 0x02)
return NULL;
uint32_t type = read_u32be(0x00,sf);
if (type == 0x00) {
loop_flag = 0;
}
else if (type == 0x02) {
loop_flag = 1;
}
else {
if (!check_extensions(sf, "btsnd"))
return NULL;
}
loop_start = read_s32be(0x04, sf); /* non-looping: 0 or some number lower than samples */
start_offset = 0x08;
channels = 2;
// maybe 'type' is just a version number and is always meant to loop?
loop_flag = false;
if (type == 0x00) {
// Petit Computer BIG (WiiU): doesn't loop (fades), Splatoon (WiiU): loops
loop_flag = loop_start > 0;
}
else if (type == 0x02) {
loop_flag = true;
}
/* extra checks since format is so simple */
data_size = get_streamfile_size(sf);
num_samples = pcm16_bytes_to_samples(data_size - start_offset, channels);

View File

@ -60,6 +60,10 @@ VGMSTREAM* init_vgmstream_fsb5_fev_bank(STREAMFILE* sf) {
case 0x534E4448: /* "SNDH" */
bank_offset = offset;
bank_size = chunk_size;
if (bank_size == 0) {
vgm_logi("FSB: bank has no subsongs (ignore)\n");
goto fail;
}
break;
default:
@ -84,10 +88,9 @@ VGMSTREAM* init_vgmstream_fsb5_fev_bank(STREAMFILE* sf) {
* 0x84: SCP Unity (PC) [~2020]
* 0x86: Hades (Switch) [~2020] */
size_t entry_size = version <= 0x28 ? 0x04 : 0x08;
int i, banks;
/* 0x00: unknown (chunk version? ex LE: 0x00080003, 0x00080005) */
banks = (bank_size - 0x04) / entry_size;
int banks = (bank_size - 0x04) / entry_size;
/* multiple banks is possible but rare [Hades (Switch), Guacamelee 2 (Switch)],
* must map bank (global) subsong to FSB (internal) subsong */
@ -97,7 +100,7 @@ VGMSTREAM* init_vgmstream_fsb5_fev_bank(STREAMFILE* sf) {
fsb5_pos = 0;
fsb5_subsong = -1;
total_subsongs = 0;
for (i = 0; i < banks; i++) {
for (int i = 0; i < banks; i++) {
//TODO: fsb5_size fails for v0x28< + encrypted, but only used with multibanks = unlikely
uint32_t fsb5_offset = read_u32le(bank_offset + 0x04 + entry_size*i + 0x00,sf);
uint32_t fsb5_size = read_u32le(bank_offset + 0x08 + entry_size*i,sf);

View File

@ -68,6 +68,7 @@ static const fsbkey_info fsbkey_list[] = {
{ MODE_FSB4, FSBKEY_ADD("AjaxIsTheGoodestBoy") }, // Hello Kitty: Island Adventure (iOS)
{ MODE_FSB5, FSBKEY_ADD("resoforce") }, // Rivals of Aether 2 (PC)
{ MODE_FSB5, FSBKEY_ADD("3cfe772db5b55b806541d3faf894020e") }, // Final Fantasy XV: War for Eos (Android)
{ MODE_FSB5, FSBKEY_ADD("aj#$kLucf2lh}eqh") }, // Forza Motorsport 2023 (PC)
/* some games use a key per file, generated from the filename
* (could add all of them but there are a lot of songs, so external .fsbkey are probably better) */

View File

@ -402,8 +402,9 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) {
* .wax: Lamborghini (Xbox)
* .voi: Sol Trigger (PSP)[ATRAC3]
* .se: Rockman X4 (PC)
* .v: Rozen Maiden: Duellwalzer (PS2)
*/
if (!check_extensions(sf, "wav,lwav,xwav,mwv,da,dax,cd,med,snd,adx,adp,xss,xsew,adpcm,adw,wd,,sbv,wvx,str,at3,rws,aud,at9,ckd,saf,ima,nsa,pcm,xvag,ogg,logg,p1d,xms,mus,dat,ldat,wma,lwma,caf,wax,voi,se")) {
if (!check_extensions(sf, "wav,lwav,xwav,mwv,da,dax,cd,med,snd,adx,adp,xss,xsew,adpcm,adw,wd,,sbv,wvx,str,at3,rws,aud,at9,ckd,saf,ima,nsa,pcm,xvag,ogg,logg,p1d,xms,mus,dat,ldat,wma,lwma,caf,wax,voi,se,v")) {
return NULL;
}

View File

@ -244,6 +244,48 @@ VGMSTREAM* init_vgmstream_sqex_sead(STREAMFILE* sf) {
}
#endif
#ifdef VGM_USE_FFMPEG
case 0x05: { /* XMA2 [Kingdom Hearts 3 (X1)] */
start_offset = sead.extradata_offset + sead.extradata_size;
/* extradata */
// 00: null?
// 03: XMA sub-version? (4)
// 04: extradata base size (without seek)
// 06: seek entries
// 08: XMA sample rate (ex. may be 47999)
// 0c: bitrate?
// 10: block size?
// 14: null?
// 18: total samples (with encoder delay)
// 1c: frame size?
// 20: null?
// 24: total samples (without encoder delay)
// 28: loop start
// 2c: loop length?
// 30+ seek table
int block_size = read_u32(sead.extradata_offset+0x10,sf);
if (!block_size)
goto fail;
int block_count = sead.stream_size + 1;
int num_samples = read_u32(sead.extradata_offset+0x24,sf);
vgmstream->codec_data = init_ffmpeg_xma2_raw(sf, start_offset, sead.stream_size, num_samples, sead.channels, sead.sample_rate, block_size, block_count);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
vgmstream->num_samples = num_samples;
vgmstream->loop_start_sample = sead.loop_start;
vgmstream->loop_end_sample = sead.loop_end;
//xma_fix_raw_samples(vgmstream, sf, start_offset, sead.stream_size, 0, 0,1);
break;
}
#endif
#ifdef VGM_USE_MPEG
case 0x06: { /* MSMP3 (MSF subfile) [Dragon Quest Builders (PS3)] */
mpeg_custom_config cfg = {0};
@ -310,7 +352,6 @@ VGMSTREAM* init_vgmstream_sqex_sead(STREAMFILE* sf) {
}
}
case 0x05: /* XMA2 (extradata may be a XMA2 fmt extra chunk) */
case 0x08: /* SWITCHOPUS (no extradata?) */
default:
vgm_logi("SQEX SEAD: unknown codec %x\n", sead.codec);