Merge pull request #1545 from EdnessP/master

- Add Evolution Games VAG variant [Rocket Power: Beach Bandits (PS2)]
- Add .RSM extension to DSP [Bully: Scholarship Edition (Wii)]
- Hide/Show SCREAM/XACT bank names if they match the input filename (like with RWS/AWD)
- Use intended AWD codec enum names
This commit is contained in:
bnnm 2024-06-14 19:41:16 +02:00 committed by GitHub
commit 135e90b84b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 170 additions and 44 deletions

View File

@ -3,7 +3,24 @@
#include "../util/endianness.h"
/* AWD - Audio Wave Dictionary (RenderWare) */
/* using their original codec names */
typedef enum {
VAG = 0x00, /* PS ADPCM */
PCM = 0x01, /* Signed 16-bit */
FLOAT = 0x02,
GCNADPCM = 0x03, /* Nintendo DSP ADPCM */
XADPCM = 0x04, /* Xbox IMA ADPCM */
WMA = 0x05, /* Windows Media Audio */
MP3 = 0x06, /* MPEG-1/2 Audio Layer III */
MP2 = 0x07, /* MPEG-1/2 Audio Layer II */
MPG = 0x08, /* MPEG-1 Audio Layer I */
AC3 = 0x09, /* Dolby AC-3 */
IMAADPCM = 0x0A /* unk: Standard? MS IMA? rws_80d uses Xbox IMA */
} awd_codec;
/* these should be all the codec indices, even if most aren't ever used
* based on the research at https://burnout.wiki/wiki/Wave_Dictionary */
/* .AWD - RenderWare Audio Wave Dictionary */
VGMSTREAM* init_vgmstream_awd(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
char file_name[STREAM_NAME_SIZE], header_name[STREAM_NAME_SIZE], stream_name[STREAM_NAME_SIZE];
@ -121,40 +138,25 @@ VGMSTREAM* init_vgmstream_awd(STREAMFILE* sf) {
else
snprintf(vgmstream->stream_name, STREAM_NAME_SIZE, "%s", stream_name);
/* these should be all the codec indices, even if most aren't ever used
* based on the research at https://burnout.wiki/wiki/Wave_Dictionary
* 0x00: PS ADPCM
* 0x01: PCM
* 0x02: Float
* 0x03: DSP ADPCM
* 0x04: Xbox IMA ADPCM
* 0x05: WMA
* 0x06: MP3
* 0x07: MP2
* 0x08: MP1
* 0x09: AC3
* 0x0A: IMA ADPCM
*/
switch (stream_codec) {
case 0x00: /* PS2 (Burnout series, Black, Call of Duty: Finest Hour) */
case VAG: /* PS2 (Burnout series, Black, Call of Duty: Finest Hour) */
vgmstream->num_samples = ps_bytes_to_samples(stream_size, channels);
vgmstream->coding_type = coding_PSX;
break;
case 0x01: /* Xbox (Burnout series, Black) */
case PCM: /* Xbox (Burnout series, Black) */
vgmstream->num_samples = pcm16_bytes_to_samples(stream_size, channels);
vgmstream->coding_type = coding_PCM16LE;
break;
case 0x03: /* GCN (Call of Duty: Finest Hour) */
case GCNADPCM: /* GCN (Call of Duty: Finest Hour) */
vgmstream->num_samples = dsp_bytes_to_samples(stream_size, channels);
dsp_read_coefs_be(vgmstream, sf, misc_data_offset + 0x1C, 0);
dsp_read_hist_be(vgmstream, sf, misc_data_offset + 0x40, 0);
vgmstream->coding_type = coding_NGC_DSP;
break;
case 0x04: /* Xbox (Black, Call of Duty: Finest Hour) */
case XADPCM: /* Xbox (Black, Call of Duty: Finest Hour) */
vgmstream->num_samples = xbox_ima_bytes_to_samples(stream_size, channels);
vgmstream->coding_type = coding_XBOX_IMA;
break;

View File

@ -30,6 +30,8 @@ typedef struct {
uint32_t table2_entry_offset;
uint32_t table3_entry_offset;
char bank_name[STREAM_NAME_SIZE];
char stream_name[STREAM_NAME_SIZE];
/* stream related */
int total_subsongs;
@ -59,10 +61,11 @@ typedef struct {
static bool parse_bnk_v3(STREAMFILE* sf, bnk_header_t* h);
/* .BNK - Sony's SCREAM bank format [The Sly Collection (PS3), Puyo Puyo Tetris (PS4), NekoBuro: Cats Block (Vita)] */
/* .BNK - Sony's 989SND/SCREAM bank format - SCRiptable Engine for Audio Manipulation
* [The Sly Collection (PS3), Puyo Puyo Tetris (PS4), NekoBuro: Cats Block (Vita)] */
VGMSTREAM* init_vgmstream_bnk_sony(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
char bank_name[STREAM_NAME_SIZE] /*[8]*/, stream_name[STREAM_NAME_SIZE] /*[16]*/;
char file_name[STREAM_NAME_SIZE];
bnk_header_t h = {0};
/* checks */
@ -85,15 +88,19 @@ VGMSTREAM* init_vgmstream_bnk_sony(STREAMFILE* sf) {
if (h.stream_name_size >= STREAM_NAME_SIZE || h.stream_name_size <= 0)
h.stream_name_size = STREAM_NAME_SIZE;
if (!h.bank_name_offset && h.stream_name_offset) {
read_string(vgmstream->stream_name, h.stream_name_size, h.stream_name_offset, sf);
}
else if (h.bank_name_offset && h.stream_name_offset) {
read_string(bank_name, h.stream_name_size, h.bank_name_offset, sf);
read_string(stream_name, h.stream_name_size, h.stream_name_offset, sf);
snprintf(vgmstream->stream_name, h.stream_name_size, "%s%s%s", bank_name, bank_name[0] == '\0' ? "" : "/", stream_name);
}
/* replace this with reading into the buffer ASAP when processing tables? */
if (h.bank_name_offset)
read_string(h.bank_name, h.stream_name_size, h.bank_name_offset, sf);
if (h.stream_name_offset)
read_string(h.stream_name, h.stream_name_size, h.stream_name_offset, sf);
if (h.stream_name[0]) {
get_streamfile_basename(sf, file_name, STREAM_NAME_SIZE);
if (h.bank_name[0] && strcmp(file_name, h.bank_name) != 0)
snprintf(vgmstream->stream_name, STREAM_NAME_SIZE, "%s/%s", h.bank_name, h.stream_name);
else
snprintf(vgmstream->stream_name, STREAM_NAME_SIZE, "%s", h.stream_name);
}
switch(h.codec) {
case DUMMY: {
@ -772,11 +779,10 @@ static bool process_data(STREAMFILE* sf, bnk_header_t* h) {
h->stream_size += 0x10;
for (offset = h->data_offset + h->stream_offset + 0x10; offset < max_offset; offset += 0x10) {
/* beginning frame (if file loops won't have end frame)
* checking the entire 16 byte block, as it is possible
* for just the first 8 bytes to be empty [Bully (PS2)] */
if (read_u32be(offset + 0x00, sf) == 0x00000000 && read_u32be(offset + 0x04, sf) == 0x00000000 &&
read_u32be(offset + 0x08, sf) == 0x00000000 && read_u32be(offset + 0x0C, sf) == 0x00000000)
/* beginning frame (if file loops won't have end frame) */
/* checking the entire 16 byte frame, as it is possible
* for just the first 8 bytes to be empty [Bully (PS2)] */
if (read_u64be(offset + 0x00, sf) == 0x00000000 && read_u64be(offset + 0x08, sf) == 0x00000000)
break;
h->stream_size += 0x10;

View File

@ -109,6 +109,7 @@ VGMSTREAM * init_vgmstream_raw_pcm(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_vag(STREAMFILE *sf);
VGMSTREAM * init_vgmstream_vag_aaap(STREAMFILE *sf);
VGMSTREAM * init_vgmstream_vag_footer(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_vag_evolution_games(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_seb(STREAMFILE *streamFile);

View File

@ -319,8 +319,9 @@ VGMSTREAM* init_vgmstream_ngc_dsp_std(STREAMFILE* sf) {
* .adp: Dr. Muto/Battalion Wars (GC), Tale of Despereaux (Wii)
* (extensionless): Tony Hawk's Downhill Jam (Wii)
* .wav: PDC World Championship Darts 2009 & Pro Tour (Wii)
* .dat: The Sims: Bustin' Out (GC) (rarely, most are extensionless) */
if (!check_extensions(sf, "dsp,adp,,wav,lwav,dat,ldat"))
* .dat: The Sims: Bustin' Out (GC) (rarely, most are extensionless)
* .rsm: Bully: Scholarship Edition (Wii) (Speech.bin) */
if (!check_extensions(sf, "dsp,adp,,wav,lwav,dat,ldat,rsm"))
return NULL;
channels = 1;
@ -600,6 +601,7 @@ fail:
return NULL;
}
/* .STE - single header + interleaved dsp [Monopoly Party! (GC)] */
VGMSTREAM* init_vgmstream_ngc_mpdsp(STREAMFILE* sf) {
dsp_meta dspm = {0};
@ -629,6 +631,7 @@ fail:
return NULL;
}
/* various dsp with differing extensions and interleave values */
VGMSTREAM* init_vgmstream_ngc_dsp_std_int(STREAMFILE* sf) {
dsp_meta dspm = {0};
@ -668,6 +671,7 @@ fail:
return NULL;
}
/* IDSP - Namco header (from NUB/NUS3) + interleaved dsp [SSB4 (3DS), Tekken Tag Tournament 2 (WiiU)] */
VGMSTREAM* init_vgmstream_idsp_namco(STREAMFILE* sf) {
dsp_meta dspm = {0};
@ -703,6 +707,7 @@ fail:
return NULL;
}
/* sadb - Procyon Studio header + interleaved dsp [Shiren the Wanderer 3 (Wii), Disaster: Day of Crisis (Wii)] */
VGMSTREAM* init_vgmstream_sadb(STREAMFILE* sf) {
dsp_meta dspm = {0};
@ -786,6 +791,7 @@ fail:
return NULL;
}
/* IDSP - from Next Level games [Super Mario Strikers (GC), Mario Strikers Charged (Wii), Spider-Man: Friend or Foe (Wii)] */
VGMSTREAM* init_vgmstream_idsp_nl(STREAMFILE* sf) {
dsp_meta dspm = {0};
@ -824,6 +830,7 @@ fail:
return NULL;
}
/* .wsd - Custom header + full interleaved dsp [Phantom Brave (Wii)] */
VGMSTREAM* init_vgmstream_wii_wsd(STREAMFILE* sf) {
dsp_meta dspm = {0};
@ -850,6 +857,7 @@ fail:
return NULL;
}
/* .ddsp - full interleaved dsp [Shark Tale (GC), The Sims series (GC/Wii), Wacky Races: Crash & Dash (Wii)] */
VGMSTREAM* init_vgmstream_dsp_ddsp(STREAMFILE* sf) {
dsp_meta dspm = {0};
@ -879,6 +887,7 @@ fail:
return NULL;
}
/* iSWS - Sumo Digital header + interleaved dsp [DiRT 2 (Wii), F1 2009 (Wii)] */
VGMSTREAM* init_vgmstream_wii_was(STREAMFILE* sf) {
dsp_meta dspm = {0};
@ -903,6 +912,7 @@ fail:
return NULL;
}
/* .str - Infogrames raw interleaved dsp [Micro Machines (GC), Superman: Shadow of Apokolips (GC)] */
VGMSTREAM* init_vgmstream_dsp_str_ig(STREAMFILE* sf) {
dsp_meta dspm = {0};
@ -925,6 +935,7 @@ fail:
return NULL;
}
/* .dsp - Ubisoft interleaved dsp with bad loop start [Speed Challenge: Jacques Villeneuve's Racing Vision (GC), XIII (GC)] */
VGMSTREAM* init_vgmstream_dsp_xiii(STREAMFILE* sf) {
dsp_meta dspm = {0};
@ -948,6 +959,7 @@ fail:
return NULL;
}
/* NPD - Icon Games header + subinterleaved DSPs [Vertigo (Wii), Build n' Race (Wii)] */
VGMSTREAM* init_vgmstream_dsp_ndp(STREAMFILE* sf) {
dsp_meta dspm = {0};
@ -978,6 +990,7 @@ fail:
return NULL;
}
/* Cabela's series (Magic Wand dev?) - header + interleaved dsp
* [Cabela's Big Game Hunt 2005 Adventures (GC), Cabela's Outdoor Adventures (GC)] */
VGMSTREAM* init_vgmstream_dsp_cabelas(STREAMFILE* sf) {
@ -1006,6 +1019,7 @@ fail:
return NULL;
}
/* AAAp - Acclaim Austin Audio header + interleaved dsp [Vexx (GC), Turok: Evolution (GC)] */
VGMSTREAM* init_vgmstream_ngc_dsp_aaap(STREAMFILE* sf) {
dsp_meta dspm = {0};
@ -1031,6 +1045,7 @@ fail:
return NULL;
}
/* DSPW - Capcom header + full interleaved DSP [Sengoku Basara 3 (Wii), Monster Hunter 3 Ultimate (WiiU)] */
VGMSTREAM* init_vgmstream_dsp_dspw(STREAMFILE* sf) {
dsp_meta dspm = {0};
@ -1077,6 +1092,7 @@ fail:
return NULL;
}
/* iadp - custom header + interleaved dsp [Dr. Muto (GC)] */
VGMSTREAM* init_vgmstream_ngc_dsp_iadp(STREAMFILE* sf) {
dsp_meta dspm = {0};
@ -1104,6 +1120,7 @@ fail:
return NULL;
}
/* .mcadpcm - Custom header + full interleaved dsp [Skyrim (Switch)] */
VGMSTREAM* init_vgmstream_dsp_mcadpcm(STREAMFILE* sf) {
dsp_meta dspm = {0};
@ -1131,6 +1148,7 @@ fail:
return NULL;
}
/* .switch_audio - UE4 standard LE header + full interleaved dsp [Gal Gun 2 (Switch)] */
VGMSTREAM* init_vgmstream_dsp_switch_audio(STREAMFILE* sf) {
dsp_meta dspm = {0};
@ -1161,6 +1179,7 @@ fail:
return NULL;
}
/* .vag - Nippon Ichi SPS wrapper [Penny-Punching Princess (Switch), Ys VIII (Switch)] */
VGMSTREAM* init_vgmstream_dsp_sps_n1(STREAMFILE* sf) {
dsp_meta dspm = {0};
@ -1191,6 +1210,7 @@ fail:
return NULL;
}
/* .itl - from Chanrinko Hero (GC) */
VGMSTREAM* init_vgmstream_dsp_itl_ch(STREAMFILE* sf) {
dsp_meta dspm = {0};
@ -1215,6 +1235,7 @@ fail:
return NULL;
}
/* ADPY - AQUASTYLE wrapper [Touhou Genso Wanderer -Reloaded- (Switch)] */
VGMSTREAM* init_vgmstream_dsp_adpy(STREAMFILE* sf) {
dsp_meta dspm = {0};
@ -1245,6 +1266,7 @@ fail:
return NULL;
}
/* ADPX - AQUASTYLE wrapper [Fushigi no Gensokyo: Lotus Labyrinth (Switch)] */
VGMSTREAM* init_vgmstream_dsp_adpx(STREAMFILE* sf) {
dsp_meta dspm = {0};
@ -1275,6 +1297,7 @@ fail:
return NULL;
}
/* .ds2 - LucasArts wrapper [Star Wars: Bounty Hunter (GC)] */
VGMSTREAM* init_vgmstream_dsp_lucasarts_ds2(STREAMFILE* sf) {
dsp_meta dspm = {0};
@ -1310,6 +1333,7 @@ fail:
return NULL;
}
/* .itl - Incinerator Studios interleaved dsp [Cars Race-o-rama (Wii), MX vs ATV Untamed (Wii)] */
VGMSTREAM* init_vgmstream_dsp_itl(STREAMFILE* sf) {
dsp_meta dspm = {0};
@ -1339,6 +1363,7 @@ VGMSTREAM* init_vgmstream_dsp_itl(STREAMFILE* sf) {
return init_vgmstream_dsp_common(sf, &dspm);
}
/* .wav - Square Enix wrapper [Dragon Quest I-III (Switch)] */
VGMSTREAM* init_vgmstream_dsp_sqex(STREAMFILE* sf) {
dsp_meta dspm = {0};
@ -1367,6 +1392,7 @@ VGMSTREAM* init_vgmstream_dsp_sqex(STREAMFILE* sf) {
return init_vgmstream_dsp_common(sf, &dspm);
}
/* WiiVoice - Koei Tecmo wrapper [Fatal Frame 5 (WiiU)] */
VGMSTREAM* init_vgmstream_dsp_wiivoice(STREAMFILE* sf) {
dsp_meta dspm = {0};

View File

@ -361,6 +361,7 @@ fail:
return NULL;
}
/* AAAp - Acclaim Austin Audio VAG header [The Red Star (PS2)] */
VGMSTREAM* init_vgmstream_vag_aaap(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
@ -417,6 +418,7 @@ fail:
return NULL;
}
/* VAGp footer - sound data first, header at the end [The Sims 2: Pets (PS2), The Sims 2: Castaway (PS2)] */
VGMSTREAM* init_vgmstream_vag_footer(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
@ -490,3 +492,80 @@ fail:
close_vgmstream(vgmstream);
return NULL;
}
/* .VAG - Evolution Games [Nickelodeon Rocket Power: Beach Bandits (PS2)] */
VGMSTREAM* init_vgmstream_vag_evolution_games(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
size_t stream_size;
off_t start_offset;
int channels, interleave, sample_rate, loop_flag;
/* checks */
if (!check_extensions(sf, "vag"))
return NULL;
/* VAGp replaced with 3 spaces + NUL */
if (!is_id32be(0x00, sf, " \0"))
return NULL;
/* all the data is in little endian */
if (read_u32le(0x04, sf) != 0) goto fail; /* version */
if (!is_id32be(0x08, sf, " \0")) goto fail; /* reserved */
stream_size = read_u32le(0x0C, sf);
sample_rate = read_u32le(0x10, sf);
/* reserved 0x14 == " "
* reserved 0x18 == " "
* reserved 0x1C == " \0"
*/
/* starting to think the padding was made with null-terminated strings */
/* data is often aligned to 0x80, but not always */
if (stream_size + 0x30 != get_streamfile_size(sf) &&
align_size_to_block(stream_size + 0x30, 0x80) != get_streamfile_size(sf))
goto fail;
/* HACK 1 */
stream_size -= 0x20;
/* technically the stream size is correct, however the final ADPCM frame
* has the end flag 0x7 stored in the coef/shift byte for whatever reason
* and the 2nd to last frame in most files has what seems like garbage(?)
* so there's an audible click at the end from those.
*/
/* HACK 2 */
if (is_id32be(0x10, sf, "tpad"))
sample_rate = 44100; /* from the GC port */
/* sample rate is valid for all files except Boostpad.vag, where this field
* is uninitialized and instead has the string "tpad" (likely from the name)
*/
channels = 1;
loop_flag = 0;
interleave = 0;
start_offset = 0x30;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_VAG_custom;
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_none;
vgmstream->sample_rate = sample_rate;
vgmstream->interleave_block_size = interleave;
vgmstream->num_samples = ps_bytes_to_samples(stream_size, channels);
read_string(vgmstream->stream_name, 0x10 + 1, 0x20, sf); /* always "Evolution Games"? */
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -86,6 +86,7 @@ VGMSTREAM* init_vgmstream_xwb(STREAMFILE* sf) {
int target_subsong = sf->stream_index;
uint32_t (*read_u32)(off_t,STREAMFILE*) = NULL;
int32_t (*read_s32)(off_t,STREAMFILE*) = NULL;
char stream_name[STREAM_NAME_SIZE], file_name[STREAM_NAME_SIZE];
/* checks */
@ -432,7 +433,7 @@ VGMSTREAM* init_vgmstream_xwb(STREAMFILE* sf) {
xwb.fix_xma_loop_samples = 1;
xwb.fix_xma_num_samples = 0;
/* Techland's XMA in tool_version 0x2a (not 0x2c?) seems to use (entry_info >> 1) num_samples
/* Techland's XMA in tool_version 0x2a (not 0x2c?) seems to use (entry_info >> 1) num_samples
* for music banks, but not sfx [Nail'd (X360)-0x2a, Dead Island (X360)-0x2c] */
if (xwb.version == XACT_TECHLAND) {
xwb.num_samples = 0;
@ -467,7 +468,16 @@ VGMSTREAM* init_vgmstream_xwb(STREAMFILE* sf) {
vgmstream->num_streams = xwb.total_subsongs;
vgmstream->stream_size = xwb.stream_size;
vgmstream->meta_type = meta_XWB;
get_name(vgmstream->stream_name,STREAM_NAME_SIZE, target_subsong, &xwb, sf);
get_name(stream_name, STREAM_NAME_SIZE, target_subsong, &xwb, sf);
if (stream_name[0]) {
get_streamfile_basename(sf, file_name, STREAM_NAME_SIZE);
if (xwb.wavebank_name[0] && strcmp(file_name, xwb.wavebank_name) != 0)
snprintf(vgmstream->stream_name, STREAM_NAME_SIZE, "%s/%s", xwb.wavebank_name, stream_name);
else
snprintf(vgmstream->stream_name, STREAM_NAME_SIZE, "%s", stream_name);
}
switch(xwb.codec) {
case PCM: /* Unreal Championship (Xbox)[PCM8], KOF2003 (Xbox)[PCM16LE], Otomedius (X360)[PCM16BE] */
@ -718,7 +728,7 @@ static void get_name(char* buf, size_t maxsize, int target_subsong, xwb_header*
if (xwb->version == 1) {
/* .wbh, a simple name container */
sf_name = open_streamfile_by_ext(sf_xwb, "wbh");
if (!sf_name) return; /* rarely found [Pac-Man World 2 (Xbox)] */
if (!sf_name) goto fail; /* rarely found [Pac-Man World 2 (Xbox)] */
name_found = get_wbh_name(buf, maxsize, target_subsong, xwb, sf_name);
close_streamfile(sf_name);
@ -726,14 +736,15 @@ static void get_name(char* buf, size_t maxsize, int target_subsong, xwb_header*
else {
/* .xsb, a comically complex cue format */
sf_name = open_xsb_filename_pair(sf_xwb);
if (!sf_name) return; /* not all xwb have xsb though */
if (!sf_name) goto fail; /* not all xwb have xsb though */
name_found = get_xsb_name(buf, maxsize, target_subsong, xwb, sf_name);
close_streamfile(sf_name);
}
if (!name_found) goto fail;
return;
if (!name_found) {
buf[0] = '\0';
}
fail:
buf[0] = '\0';
}

View File

@ -50,6 +50,7 @@ init_vgmstream_t init_vgmstream_functions[] = {
init_vgmstream_vag,
init_vgmstream_vag_aaap,
init_vgmstream_vag_footer,
init_vgmstream_vag_evolution_games,
init_vgmstream_ild,
init_vgmstream_ngc_str,
init_vgmstream_ea_schl,