diff --git a/doc/TXTH.md b/doc/TXTH.md index 5e9d97b8..c06fb88a 100644 --- a/doc/TXTH.md +++ b/doc/TXTH.md @@ -1100,3 +1100,24 @@ codec = XBOX num_samples = data_size #todo: there are dummy entries ``` + +#### Machi-ing Maker 4 (X360) .xma.txth +``` +codec = XMA2 + +#00: id (0x819A584D) +#04: null +#08: fmt header offset +#0c: fmt size +start_offset = @0x10:BE +data_size = @0x14:BE + +base_offset = @0x08:BE +channels = @0x02:BE$2 +sample_rate = @0x04:BE + +num_samples = @0x24:BE +loop_end = @0x24:BE #0x2c? +loop_start = @0x28:BE +loop_flag = @0x2c:BE +``` diff --git a/src/meta/adx_keys.h b/src/meta/adx_keys.h index 616f2355..829b7a77 100644 --- a/src/meta/adx_keys.h +++ b/src/meta/adx_keys.h @@ -252,6 +252,9 @@ static const adxkey_info adxkey9_list[] = { /* Assault Lily Last Bullet (Android) */ {0x0000,0x0000,0x0000, NULL,6349046567469313}, // 00168E6C99510101 (+ AWB subkeys) + /* maimai DX Splash (AC) */ + {0x0000,0x0000,0x0000, NULL,9170825592834449000}, // 7F4551499DF55E68 + }; static const int adxkey8_list_count = sizeof(adxkey8_list) / sizeof(adxkey8_list[0]); diff --git a/src/meta/ea_schl.c b/src/meta/ea_schl.c index 25d8fb79..20fbc908 100644 --- a/src/meta/ea_schl.c +++ b/src/meta/ea_schl.c @@ -23,7 +23,7 @@ #define EA_PLATFORM_X360 0x09 #define EA_PLATFORM_PSP 0x0A #define EA_PLATFORM_PS3 0x0E /* very rare [Need for Speed: Carbon (PS3)] */ -#define EA_PLATFORM_WII 0x10 /* not seen so far */ +#define EA_PLATFORM_WII 0x10 /* not seen so far (sx.exe samples ok) */ #define EA_PLATFORM_3DS 0x14 /* codec constants (undefined are probably reserved, ie.- sx.exe encodes PCM24/DVI but no platform decodes them) */ @@ -48,19 +48,19 @@ #define EA_CODEC2_S16LE 0x08 #define EA_CODEC2_S8 0x09 #define EA_CODEC2_EAXA 0x0A -//#define EA_CODEC2_U8_INT 0x0B /* not used */ -//#define EA_CODEC2_CDXA 0x0C /* not used */ -//#define EA_CODEC2_IMA 0x0D /* not used */ -//#define EA_CODEC2_LAYER1 0x0E /* not used */ +//#define EA_CODEC2_U8_INT 0x0B /* not used (sx.exe internal defs) */ +//#define EA_CODEC2_CDXA 0x0C /* not used (sx.exe internal defs) */ +//#define EA_CODEC2_IMA 0x0D /* not used (sx.exe internal defs) */ +//#define EA_CODEC2_LAYER1 0x0E /* not used (sx.exe internal defs) */ #define EA_CODEC2_LAYER2 0x0F #define EA_CODEC2_LAYER3 0x10 /* not seen so far but may be used somewhere */ #define EA_CODEC2_GCADPCM 0x12 -//#define EA_CODEC2_S24LE_INT 0x13 /* not used */ +//#define EA_CODEC2_S24LE_INT 0x13 /* not used (sx.exe internal defs) */ #define EA_CODEC2_XBOXADPCM 0x14 -//#define EA_CODEC2_S24BE_INT 0x15 /* not used */ +//#define EA_CODEC2_S24BE_INT 0x15 /* not used (sx.exe internal defs) */ #define EA_CODEC2_MT5 0x16 #define EA_CODEC2_EALAYER3 0x17 -//#define EA_CODEC2_ATRAC3 0x1A /* not seen so far */ +#define EA_CODEC2_ATRAC3 0x1A /* not seen so far (sx.exe samples ok) */ #define EA_CODEC2_ATRAC3PLUS 0x1B /* Block headers, SCxy - where x is block ID and y is endianness flag (always 'l'?) */ @@ -127,7 +127,7 @@ static VGMSTREAM * parse_bnk_header(STREAMFILE* sf, off_t offset, int target_str static int parse_variable_header(STREAMFILE* sf, ea_header* ea, off_t begin_offset, int max_length, int bnk_version); static uint32_t read_patch(STREAMFILE* sf, off_t* offset); static off_t get_ea_stream_mpeg_start_offset(STREAMFILE* sf, off_t start_offset, const ea_header* ea); -static VGMSTREAM * init_vgmstream_ea_variable_header(STREAMFILE* sf, ea_header* ea, off_t start_offset, int is_bnk, int standalone); +static VGMSTREAM* init_vgmstream_ea_variable_header(STREAMFILE* sf, ea_header* ea, off_t start_offset, int is_bnk, int standalone); static void update_ea_stream_size_and_samples(STREAMFILE* sf, off_t start_offset, VGMSTREAM* vgmstream, int standalone); /* EA SCHl with variable header - from EA games (roughly 1997~2010); generated by EA Canada's sx.exe/Sound eXchange */ @@ -182,7 +182,7 @@ fail: } /* EA SCHl inside non-demuxed videos, used in current gen games too */ -VGMSTREAM * init_vgmstream_ea_schl_video(STREAMFILE* sf) { +VGMSTREAM* init_vgmstream_ea_schl_video(STREAMFILE* sf) { VGMSTREAM* vgmstream = NULL; off_t offset = 0, start_offset = 0; int blocks_done = 0; @@ -277,7 +277,7 @@ fail: } /* EA BNK with variable header - from EA games SFXs; also created by sx.exe */ -VGMSTREAM * init_vgmstream_ea_bnk(STREAMFILE* sf) { +VGMSTREAM* init_vgmstream_ea_bnk(STREAMFILE* sf) { int target_stream = sf->stream_index; /* check extension */ @@ -299,7 +299,7 @@ fail: /* EA ABK - common soundbank format in 6th-gen games, can reference RAM and streamed assets */ /* RAM assets are stored in embedded BNK file */ /* streamed assets are stored externally in AST file (mostly seen in earlier 6th-gen games) */ -VGMSTREAM * init_vgmstream_ea_abk(STREAMFILE* sf) { +VGMSTREAM* init_vgmstream_ea_abk(STREAMFILE* sf) { int bnk_target_stream, is_dupe, total_sounds = 0, target_stream = sf->stream_index; off_t bnk_offset, modules_table, module_data, player_offset, samples_table, entry_offset, target_entry_offset, schl_offset, schl_loop_offset; uint32_t i, j, k, num_sounds, num_sample_tables; @@ -561,7 +561,7 @@ fail: } /* EA HDR/DAT v2 (2006-2014) */ -VGMSTREAM * init_vgmstream_ea_hdr_dat_v2(STREAMFILE* sf) { +VGMSTREAM* init_vgmstream_ea_hdr_dat_v2(STREAMFILE* sf) { VGMSTREAM *vgmstream; STREAMFILE *sf_dat = NULL; int target_stream = sf->stream_index; @@ -646,20 +646,18 @@ static STREAMFILE* open_mapfile_pair(STREAMFILE* sf, int track, int num_tracks) {"SSX4FE.mpf", "TrackFE.mus"}, /* SSX On Tour */ {"SSX4Path.mpf", "Track.mus"}, {"SSX4.mpf", "moments0.mus,main.mus,load_loop0.mus"}, /* SSX Blur */ - {"*.mpf", "*_main.mus"}, /* 007 - Everything or Nothing */ - /* TODO: need better wildcard support + {"*.mpf", "*_main.mus"}, /* 007: Everything or Nothing */ + /* EA loads pairs manually, so complex cases needs .txtm to map * NSF2: - * ZTRxxROK.MAP > ZTRxx.TRJ - * ZTRxxTEC.MAP > ZTRxx.TRM - * ZZSHOW.MAP and ZZSHOW2.MAP > ZZSHOW.MUS + * - ZTRxxROK.MAP > ZTRxx.TRJ + * - ZTRxxTEC.MAP > ZTRxx.TRM + * - ZZSHOW.MAP and ZZSHOW2.MAP > ZZSHOW.MUS * NSF3: - * ZTRxxROK.MAP > ZZZTRxxA.TRJ - * ZTRxxTEC.MAP > ZZZTRxxB.TRM - * ZTR00R0A.MAP and ZTR00R0B.MAP > ZZZTR00A.TRJ - * other extra files that may need the hack below + * - ZTRxxROK.MAP > ZZZTRxxA.TRJ + * - ZTRxxTEC.MAP > ZZZTRxxB.TRM + * - ZTR00R0A.MAP and ZTR00R0B.MAP > ZZZTR00A.TRJ * SSX 3: - * *.mpf > *.mus,xxloops0.mus - * really need to think of something for this + * - *.mpf > *.mus,xxloops0.mus */ }; STREAMFILE* sf_mus = NULL; @@ -744,7 +742,7 @@ static STREAMFILE* open_mapfile_pair(STREAMFILE* sf, int track, int num_tracks) /* EA MAP/MUS combo - used in older games for interactive music (for EA's PathFinder tool) */ /* seen in Need for Speed II, Need for Speed III: Hot Pursuit, SSX */ -VGMSTREAM * init_vgmstream_ea_map_mus(STREAMFILE* sf) { +VGMSTREAM* init_vgmstream_ea_map_mus(STREAMFILE* sf) { VGMSTREAM* vgmstream = NULL; STREAMFILE* sf_mus = NULL; uint8_t version, num_sounds, num_events, num_sections; @@ -809,7 +807,7 @@ fail: } /* EA MPF/MUS combo - used in 6th gen games for interactive music (for EA's PathFinder tool) */ -VGMSTREAM * init_vgmstream_ea_mpf_mus(STREAMFILE* sf) { +VGMSTREAM* init_vgmstream_ea_mpf_mus(STREAMFILE* sf) { VGMSTREAM* vgmstream = NULL; STREAMFILE* sf_mus = NULL; segmented_layout_data *data_s = NULL; @@ -1102,7 +1100,7 @@ fail: } /* EA SCHl with variable header - from EA games (roughly 1997~2010); generated by EA Canada's sx.exe/Sound eXchange */ -static VGMSTREAM * parse_schl_block(STREAMFILE* sf, off_t offset, int standalone) { +static VGMSTREAM* parse_schl_block(STREAMFILE* sf, off_t offset, int standalone) { off_t start_offset, header_offset; size_t header_size; uint32_t header_id; @@ -1138,7 +1136,7 @@ fail: } /* EA BNK with variable header - from EA games SFXs; also created by sx.exe */ -static VGMSTREAM * parse_bnk_header(STREAMFILE* sf, off_t offset, int target_stream, int is_embedded) { +static VGMSTREAM* parse_bnk_header(STREAMFILE* sf, off_t offset, int target_stream, int is_embedded) { uint32_t i; uint16_t num_sounds; off_t header_offset, start_offset, test_offset, table_offset, entry_offset; @@ -1235,8 +1233,8 @@ fail: } /* inits VGMSTREAM from a EA header */ -static VGMSTREAM * init_vgmstream_ea_variable_header(STREAMFILE* sf, ea_header* ea, off_t start_offset, int bnk_version, int standalone) { - VGMSTREAM * vgmstream = NULL; +static VGMSTREAM* init_vgmstream_ea_variable_header(STREAMFILE* sf, ea_header* ea, off_t start_offset, int bnk_version, int standalone) { + VGMSTREAM* vgmstream = NULL; int i, ch; int is_bnk = bnk_version; @@ -1372,10 +1370,12 @@ static VGMSTREAM * init_vgmstream_ea_variable_header(STREAMFILE* sf, ea_header* break; #ifdef VGM_USE_FFMPEG - case EA_CODEC2_ATRAC3PLUS: { /* ATRAC3+ */ - /* regular ATRAC3plus chunked in SCxx blocks, including RIFF header [Medal of Honor Heroes 2 (PSP)] */ + //case EA_CODEC2_ATRAC3: /* works but commented to catch games using it */ + case EA_CODEC2_ATRAC3PLUS: { /* ATRAC3plus [Medal of Honor Heroes 2 (PSP)] */ + /* data chunked in SCxx blocks, including RIFF header */ if (!is_bnk) { STREAMFILE* temp_sf = NULL; + /* remove blocks on reads to feed FFmpeg a clean .at3 */ temp_sf = setup_schl_streamfile(sf, ea->codec2, ea->channels, start_offset, 0); if (!temp_sf) goto fail; diff --git a/src/meta/ea_schl_streamfile.h b/src/meta/ea_schl_streamfile.h index e2711b77..3822ae62 100644 --- a/src/meta/ea_schl_streamfile.h +++ b/src/meta/ea_schl_streamfile.h @@ -16,6 +16,7 @@ static void block_callback(STREAMFILE *sf, deblock_io_data *data) { return; switch(data->cfg.codec) { + case 0x1a: /* ATRAC3 */ case 0x1b: /* ATRAC3plus */ data->data_size = read_32bitLE(data->physical_offset + 0x0c + 0x04 * data->cfg.channels, sf); data->skip_size = 0x0c + 0x04 * data->cfg.channels + 0x04; diff --git a/src/meta/hca_keys.h b/src/meta/hca_keys.h index dcf1b4d9..0700949e 100644 --- a/src/meta/hca_keys.h +++ b/src/meta/hca_keys.h @@ -404,6 +404,9 @@ static const hcakey_info hcakey_list[] = { /* Dragalia Lost (iOS/Android) */ {2967411924141}, // 000002B2E7889CAD + /* maimai DX Splash (AC) */ + {9170825592834449000}, // 7F4551499DF55E68 + /* D4DJ Groovy Mix (Android) [base files] */ {393410674916959300}, // 0575ACECA945A444 /* D4DJ Groovy Mix (Android) [music_* files, per-song later mixed with subkey] */ diff --git a/src/meta/sps_n1.c b/src/meta/sps_n1.c index 8e26967c..7a55020d 100644 --- a/src/meta/sps_n1.c +++ b/src/meta/sps_n1.c @@ -4,7 +4,7 @@ /* also see init_vgmstream_dsp_sps_n1 and init_vgmstream_opus_sps_n1 */ -/* Nippon Ichi SPS wrapper [ClaDun (PSP)] */ +/* Nippon Ichi SPS wrapper [ClaDun (PSP), Legasista (PS3)] */ VGMSTREAM* init_vgmstream_sps_n1(STREAMFILE* sf) { VGMSTREAM* vgmstream = NULL; STREAMFILE* temp_sf = NULL; @@ -14,15 +14,24 @@ VGMSTREAM* init_vgmstream_sps_n1(STREAMFILE* sf) { VGMSTREAM* (*init_vgmstream_subfile)(STREAMFILE*) = NULL; const char* extension; - + uint32_t (*read_u32)(off_t,STREAMFILE*); + uint16_t (*read_u16)(off_t,STREAMFILE*); /* checks */ if (!check_extensions(sf,"sps")) goto fail; - type = read_u32le(0x00,sf); - subfile_size = read_u32le(0x04,sf); - sample_rate = read_u16le(0x08,sf); + if (guess_endianness32bit(0x00, sf)) { /* PS3 */ + read_u32 = read_u32be; + read_u16 = read_u16be; + } + else { + read_u32 = read_u32le; + read_u16 = read_u16le; + } + type = read_u32(0x00,sf); + subfile_size = read_u32(0x04,sf); + sample_rate = read_u16(0x08,sf); /* 0x0a: flag? (stereo?) */ /* 0x0b: flag? */ /* 0x0c: num_samples */