diff --git a/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj b/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj index 9a671d41c..3879cde40 100644 --- a/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj +++ b/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj @@ -586,6 +586,8 @@ 83AFABBC23795202002F3947 /* xssb.c in Sources */ = {isa = PBXBuildFile; fileRef = 83AFABB923795201002F3947 /* xssb.c */; }; 83AFABBD23795202002F3947 /* ea_eaac_opus_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 83AFABBA23795202002F3947 /* ea_eaac_opus_streamfile.h */; }; 83AFABBE23795202002F3947 /* isb.c in Sources */ = {isa = PBXBuildFile; fileRef = 83AFABBB23795202002F3947 /* isb.c */; }; + 83B46FD12707FB2100847FC9 /* at3plus_decoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 83B46FCD2707FB2100847FC9 /* at3plus_decoder.h */; }; + 83B46FD52707FB9A00847FC9 /* endianness.h in Headers */ = {isa = PBXBuildFile; fileRef = 83B46FD42707FB9A00847FC9 /* endianness.h */; }; 83BAFB6C19F45EB3005DAB60 /* bfstm.c in Sources */ = {isa = PBXBuildFile; fileRef = 83BAFB6B19F45EB3005DAB60 /* bfstm.c */; }; 83C7280F22BC893D00678B4A /* xwb_xsb.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C727FB22BC893800678B4A /* xwb_xsb.h */; }; 83C7281022BC893D00678B4A /* nps.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C727FC22BC893900678B4A /* nps.c */; }; @@ -1394,6 +1396,8 @@ 83AFABB923795201002F3947 /* xssb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xssb.c; sourceTree = ""; }; 83AFABBA23795202002F3947 /* ea_eaac_opus_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ea_eaac_opus_streamfile.h; sourceTree = ""; }; 83AFABBB23795202002F3947 /* isb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = isb.c; sourceTree = ""; }; + 83B46FCD2707FB2100847FC9 /* at3plus_decoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = at3plus_decoder.h; sourceTree = ""; }; + 83B46FD42707FB9A00847FC9 /* endianness.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = endianness.h; sourceTree = ""; }; 83BAFB6B19F45EB3005DAB60 /* bfstm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bfstm.c; sourceTree = ""; }; 83C727FB22BC893800678B4A /* xwb_xsb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = xwb_xsb.h; sourceTree = ""; }; 83C727FC22BC893900678B4A /* nps.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nps.c; sourceTree = ""; }; @@ -1631,6 +1635,7 @@ 836F6DE218BDC2180095E648 /* adx_decoder.c */, 8315958320FEC831007002F0 /* asf_decoder.c */, 8306B08120984517000302D4 /* at3plus_decoder.c */, + 83B46FCD2707FB2100847FC9 /* at3plus_decoder.h */, 830EBE0F2004655D0023AA10 /* atrac9_decoder.c */, 834FE0B2215C798C000A5D3D /* celt_fsb_decoder.c */, 83031EBF243C50A800C3F3E0 /* circus_decoder_lib_data.h */, @@ -2253,6 +2258,7 @@ children = ( 83D26A8026E66DC2001A9475 /* chunks.c */, 83D26A7E26E66DC2001A9475 /* chunks.h */, + 83B46FD42707FB9A00847FC9 /* endianness.h */, 83D26A7D26E66DC2001A9475 /* log.c */, 83D26A7F26E66DC2001A9475 /* log.h */, 8315868826F586F900803A3A /* m2_psb.c */, @@ -2319,6 +2325,7 @@ 83E7FD6225EF2B0C00683FD2 /* tac_decoder_lib_ops.h in Headers */, 83AF2CCC26226BA500538240 /* encrypted_bgm_streamfile.h in Headers */, 8349A90F1FE6258200E26435 /* aix_streamfile.h in Headers */, + 83B46FD52707FB9A00847FC9 /* endianness.h in Headers */, 836F705718BDC2190095E648 /* util.h in Headers */, 83C7282722BC8C1500678B4A /* plugins.h in Headers */, 834FE0ED215C79ED000A5D3D /* fsb_interleave_streamfile.h in Headers */, @@ -2333,6 +2340,7 @@ 8306B0E020984590000302D4 /* ppst_streamfile.h in Headers */, 83AA7F722519BFEA004C5298 /* vorbis_bitreader.h in Headers */, 834FE0BA215C798C000A5D3D /* ea_mt_decoder_utk.h in Headers */, + 83B46FD12707FB2100847FC9 /* at3plus_decoder.h in Headers */, 835C883722CC17BE001B4B3F /* ogg_vorbis_streamfile.h in Headers */, 837CEAFE23487F2C00E62A4A /* jstm_streamfile.h in Headers */, 832BF82021E0514B006F50F1 /* zsnd_streamfile.h in Headers */, diff --git a/Frameworks/vgmstream/vgmstream/src/coding/at3plus_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/at3plus_decoder.c index 9347d8a73..13a99ee0e 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/at3plus_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/at3plus_decoder.c @@ -3,14 +3,7 @@ #ifdef VGM_USE_MAIATRAC3PLUS #include "maiatrac3plus.h" - -struct maiatrac3plus_codec_data { - sample_t* buffer; - int channels; - int samples_discard; - void* handle; -}; - +#include "at3plus_decoder.h" maiatrac3plus_codec_data *init_at3plus() { diff --git a/Frameworks/vgmstream/vgmstream/src/coding/at3plus_decoder.h b/Frameworks/vgmstream/vgmstream/src/coding/at3plus_decoder.h new file mode 100644 index 000000000..08093eff1 --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/coding/at3plus_decoder.h @@ -0,0 +1,11 @@ +#ifndef _AT3PLUS_DECODER_H +#define _AT3PLUS_DECODER_H + +struct maiatrac3plus_codec_data { + sample_t* buffer; + int channels; + int samples_discard; + void* handle; +}; + +#endif diff --git a/Frameworks/vgmstream/vgmstream/src/coding/coding.h b/Frameworks/vgmstream/vgmstream/src/coding/coding.h index d586264ad..3d05f987d 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/coding.h +++ b/Frameworks/vgmstream/vgmstream/src/coding/coding.h @@ -680,7 +680,7 @@ size_t atrac3plus_bytes_to_samples(size_t bytes, int full_block_align); size_t ac3_bytes_to_samples(size_t bytes, int full_block_align, int channels); size_t aac_get_samples(STREAMFILE* sf, off_t start_offset, size_t bytes); size_t mpeg_get_samples(STREAMFILE* sf, off_t start_offset, size_t bytes); -int32_t mpeg_get_samples_clean(STREAMFILE* sf, off_t start, size_t size, size_t* p_loop_start, size_t* p_loop_end, int is_vbr); +int32_t mpeg_get_samples_clean(STREAMFILE* sf, off_t start, size_t size, uint32_t* p_loop_start, uint32_t* p_loop_end, int is_vbr); int mpc_get_samples(STREAMFILE* sf, off_t offset, int32_t* p_samples, int32_t* p_delay); diff --git a/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder.c index 54b09ccaf..e363f5afc 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder.c @@ -55,7 +55,7 @@ struct ffmpeg_codec_data { }; -#define FFMPEG_DEFAULT_IO_BUFFER_SIZE 128 * 1024 +#define FFMPEG_DEFAULT_IO_BUFFER_SIZE STREAMFILE_DEFAULT_BUFFER_SIZE static volatile int g_ffmpeg_initialized = 0; @@ -322,7 +322,7 @@ ffmpeg_codec_data* init_ffmpeg_header_offset_subsong(STREAMFILE* sf, uint8_t* he goto fail; if (size == 0 || start + size > get_streamfile_size(sf)) { - vgm_asserti(size != 0, "FFMPEG: wrong start+size found: %x + %x > %x \n", (uint32_t)start, (uint32_t)size, get_streamfile_size(sf)); + vgm_asserti(size != 0, "FFMPEG: wrong start+size found: %x + %x > %x \n", (uint32_t)start, (uint32_t)size, (uint32_t)get_streamfile_size(sf)); size = get_streamfile_size(sf) - start; } diff --git a/Frameworks/vgmstream/vgmstream/src/coding/mpeg_custom_utils.c b/Frameworks/vgmstream/vgmstream/src/coding/mpeg_custom_utils.c index 82abed465..f3cb4508f 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/mpeg_custom_utils.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/mpeg_custom_utils.c @@ -451,7 +451,7 @@ size_t mpeg_get_samples(STREAMFILE* sf, off_t start_offset, size_t bytes) { /* variation of the above, for clean streams = no ID3/VBR headers * (maybe should be fused in a single thing with config, API is kinda messy too) */ -int32_t mpeg_get_samples_clean(STREAMFILE *sf, off_t start, size_t size, size_t* p_loop_start, size_t* p_loop_end, int is_vbr) { +int32_t mpeg_get_samples_clean(STREAMFILE* sf, off_t start, size_t size, uint32_t* p_loop_start, uint32_t* p_loop_end, int is_vbr) { mpeg_frame_info info; off_t offset = start; int32_t num_samples = 0, loop_start = 0, loop_end = 0; diff --git a/Frameworks/vgmstream/vgmstream/src/coding/vorbis_custom_utils_vid1.c b/Frameworks/vgmstream/vgmstream/src/coding/vorbis_custom_utils_vid1.c index 6da8c264b..327a1f200 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/vorbis_custom_utils_vid1.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/vorbis_custom_utils_vid1.c @@ -1,9 +1,9 @@ #include "vorbis_custom_decoder.h" +#ifdef VGM_USE_VORBIS #define BITSTREAM_READ_ONLY /* config */ #include "vorbis_bitreader.h" -#ifdef VGM_USE_VORBIS #include diff --git a/Frameworks/vgmstream/vgmstream/src/coding/vorbis_custom_utils_wwise.c b/Frameworks/vgmstream/vgmstream/src/coding/vorbis_custom_utils_wwise.c index cc7dc2858..54d4a39f5 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/vorbis_custom_utils_wwise.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/vorbis_custom_utils_wwise.c @@ -1,7 +1,7 @@ #include "vorbis_custom_decoder.h" -#include "vorbis_bitreader.h" #ifdef VGM_USE_VORBIS +#include "vorbis_bitreader.h" #include #define WWISE_VORBIS_USE_PRECOMPILED_WVC 1 /* if enabled vgmstream weights ~150kb more but doesn't need external .wvc packets */ diff --git a/Frameworks/vgmstream/vgmstream/src/decode.c b/Frameworks/vgmstream/vgmstream/src/decode.c index 4280ace54..70b23b924 100644 --- a/Frameworks/vgmstream/vgmstream/src/decode.c +++ b/Frameworks/vgmstream/vgmstream/src/decode.c @@ -4,6 +4,9 @@ #include "coding/coding.h" #include "mixing.h" #include "plugins.h" +#ifdef VGM_USE_MAIATRAC3PLUS +#include "at3plus_decoder.h" +#endif /* custom codec handling, not exactly "decode" stuff but here to simplify adding new codecs */ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/acb.c b/Frameworks/vgmstream/vgmstream/src/meta/acb.c index 4929633b6..e51cc67a2 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/acb.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/acb.c @@ -47,7 +47,7 @@ VGMSTREAM* init_vgmstream_acb(STREAMFILE* sf) { } } - //;VGM_LOG("ACB: subfile offset=%lx + %x\n", subfile_offset, subfile_size); + //;VGM_LOG("acb: subfile offset=%lx + %x\n", subfile_offset, subfile_size); temp_sf = setup_subfile_streamfile(sf, subfile_offset,subfile_size, "awb"); if (!temp_sf) goto fail; @@ -93,19 +93,11 @@ fail: #define ACB_MAX_NAME 1024 /* even more is possible in rare cases [Senran Kagura Burst Re:Newal (PC)] */ #define ACB_MAX_BUFFER 0x8000 -#define ACB_PRELOAD 1 //todo: remove non-preloading code static STREAMFILE* setup_acb_streamfile(STREAMFILE* sf, size_t buffer_size) { STREAMFILE* new_sf = NULL; -#ifndef ACB_PRELOAD - /* buffer seems better than reopening when opening multiple subsongs at the same time with STDIO, - * even though there is more buffer trashing, maybe concurrent IO is slower */ - new_sf = open_wrap_streamfile(sf); - new_sf = open_buffer_streamfile_f(new_sf, buffer_size); -#else new_sf = reopen_streamfile(sf, buffer_size); -#endif return new_sf; } @@ -139,10 +131,8 @@ typedef struct { uint16_t NumTracks; uint32_t TrackIndex_offset; uint32_t TrackIndex_size; - uint16_t ActionTrackStartIndex; - uint16_t NumActionTracks; - uint32_t TrackValues_offset; - uint32_t TrackValues_size; + //uint16_t ActionTrackStartIndex; + //uint16_t NumActionTracks; uint8_t Type; } Sequence_t; @@ -173,19 +163,8 @@ typedef struct { /* keep track of these tables so they can be closed when done */ utf_context* Header; - utf_context* TempTable; + utf_context* CueNames; - utf_context* CueNameTable; - utf_context* CueTable; - utf_context* BlockSequenceTable; - utf_context* BlockTable; - utf_context* SequenceTable; - utf_context* TrackTable; - utf_context* TrackCommandTable; - utf_context* SynthTable; - utf_context* WaveformTable; - - STREAMFILE* TempSf; STREAMFILE* CueNameSf; STREAMFILE* CueSf; STREAMFILE* BlockSequenceSf; @@ -216,17 +195,10 @@ typedef struct { int Synth_rows; int Waveform_rows; - uint8_t* buf; - int buf_size; - /* config */ int is_memory; int target_waveid; int target_port; - //todo remove - int has_TrackEventTable; - int has_CommandTable; - int is_preload; /* to avoid infinite/circular references (AtomViewer crashes otherwise) */ int synth_depth; @@ -238,34 +210,9 @@ typedef struct { int awbname_count; int16_t awbname_list[ACB_MAX_NAMELIST]; char name[ACB_MAX_NAME]; - - } acb_header; -static int read_buffer(acb_header* acb, uint32_t offset, uint32_t size, STREAMFILE* sf) { - int bytes; - - if (acb->buf_size < size) { - if (size > ACB_MAX_BUFFER) { - VGM_LOG("ACB: buffer too big: %x\n", size); - goto fail; - } - /* could realloc and stuff but... */ - acb->buf_size = ACB_MAX_BUFFER; - acb->buf = malloc(acb->buf_size * sizeof(uint8_t)); - if (!acb->buf) goto fail; - } - - - bytes = read_streamfile(acb->buf, offset, size, sf); - if (bytes != size) goto fail; - - return 1; -fail: - VGM_LOG("ACB: failed buffer"); - return 0; -} static int open_utf_subtable(acb_header* acb, STREAMFILE* *TableSf, utf_context* *Table, const char* TableName, int* rows, int buffer) { uint32_t offset = 0; @@ -283,7 +230,7 @@ static int open_utf_subtable(acb_header* acb, STREAMFILE* *TableSf, utf_context* *Table = utf_open(*TableSf, offset, rows, NULL); if (!*Table) goto fail; - //;VGM_LOG("ACB: loaded table %s\n", TableName); + //;VGM_LOG("acb: loaded table %s\n", TableName); return 1; fail: return 0; @@ -306,7 +253,7 @@ static void acb_cpy(char* dst, int dst_max, const char* src) { static void add_acb_name(acb_header* acb, int8_t Streaming) { if (!acb->cuename_name) { - VGM_LOG("ACB: no name\n"); + //;VGM_LOG("acb: no name\n"); return; } @@ -336,7 +283,7 @@ static void add_acb_name(acb_header* acb, int8_t Streaming) { if (acb->awbname_count >= ACB_MAX_NAMELIST) acb->awbname_count = ACB_MAX_NAMELIST - 1; /* ??? */ - //;VGM_LOG("ACB: found cue for waveid=%i: %s\n", acb->target_waveid, acb->cuename_name); + //;VGM_LOG("acb: found cue for waveid=%i: %s\n", acb->target_waveid, acb->cuename_name); } @@ -344,7 +291,7 @@ static void add_acb_name(acb_header* acb, int8_t Streaming) { /* OBJECT HANDLERS */ static int preload_acb_waveform(acb_header* acb) { - utf_context* Table = acb->WaveformTable; + utf_context* Table = NULL; int* p_rows = &acb->Waveform_rows; int i, c_Id, c_MemoryAwbId, c_StreamAwbId, c_StreamAwbPortNo, c_Streaming; @@ -354,7 +301,7 @@ static int preload_acb_waveform(acb_header* acb) { goto fail; if (!*p_rows) return 1; - ;VGM_LOG("acb: preload Waveform=%i\n", *p_rows); + //;VGM_LOG("acb: preload Waveform=%i\n", *p_rows); acb->Waveform = malloc(*p_rows * sizeof(Waveform_t)); if (!acb->Waveform) goto fail; @@ -383,47 +330,21 @@ static int preload_acb_waveform(acb_header* acb) { utf_query_col_u8(Table, i, c_Streaming, &r->Streaming); } - ;VGM_LOG("acb: preload Waveform done\n"); + utf_close(Table); return 1; fail: - VGM_LOG("ACB: failed Waveform preload\n"); + VGM_LOG("acb: failed Waveform preload\n"); + utf_close(Table); return 0; } static int load_acb_waveform(acb_header* acb, uint16_t Index) { Waveform_t* r; - Waveform_t tmp; - /* read Waveform[Index] */ - if (acb->is_preload) { - if (!preload_acb_waveform(acb)) goto fail; - if (Index > acb->Waveform_rows) goto fail; - r = &acb->Waveform[Index]; - } - else { - r = &tmp; - if (!open_utf_subtable(acb, &acb->WaveformSf, &acb->WaveformTable, "WaveformTable", NULL, ACB_TABLE_BUFFER_WAVEFORM)) - goto fail; - - if (!utf_query_u16(acb->WaveformTable, Index, "Id", &r->Id)) { /* older versions use Id */ - if (acb->is_memory) { - if (!utf_query_u16(acb->WaveformTable, Index, "MemoryAwbId", &r->Id)) - goto fail; - r->PortNo = 0xFFFF; - } else { - if (!utf_query_u16(acb->WaveformTable, Index, "StreamAwbId", &r->Id)) - goto fail; - if (!utf_query_u16(acb->WaveformTable, Index, "StreamAwbPortNo", &r->PortNo)) - r->PortNo = 0; /* assumed */ - } - } - else { - r->PortNo = 0xFFFF; - } - if (!utf_query_u8(acb->WaveformTable, Index, "Streaming", &r->Streaming)) - goto fail; - //;VGM_LOG("ACB: Waveform[%i]: Id=%i, PortNo=%i, Streaming=%i\n", Index, r->Id, r->PortNo, r->Streaming); - } + if (!preload_acb_waveform(acb)) goto fail; + if (Index > acb->Waveform_rows) goto fail; + r = &acb->Waveform[Index]; + //;VGM_LOG("acb: Waveform[%i]: Id=%i, PortNo=%i, Streaming=%i\n", Index, r->Id, r->PortNo, r->Streaming); /* not found but valid */ if (r->Id != acb->target_waveid) @@ -442,7 +363,7 @@ static int load_acb_waveform(acb_header* acb, uint16_t Index) { return 1; fail: - VGM_LOG("ACB: failed Waveform %i\n", Index); + VGM_LOG("acb: failed Waveform %i\n", Index); return 0; } @@ -452,7 +373,7 @@ fail: static int load_acb_sequence(acb_header* acb, uint16_t Index); static int preload_acb_synth(acb_header* acb) { - utf_context* Table = acb->SynthTable; + utf_context* Table = NULL; int* p_rows = &acb->Synth_rows; int i, c_Type, c_ReferenceItems; @@ -462,7 +383,7 @@ static int preload_acb_synth(acb_header* acb) { goto fail; if (!*p_rows) return 1; - ;VGM_LOG("acb: preload Synth=%i\n", *p_rows); + //;VGM_LOG("acb: preload Synth=%i\n", *p_rows); acb->Synth = malloc(*p_rows * sizeof(Synth_t)); if (!acb->Synth) goto fail; @@ -475,51 +396,36 @@ static int preload_acb_synth(acb_header* acb) { utf_query_col_u8(Table, i, c_Type, &r->Type); utf_query_col_data(Table, i, c_ReferenceItems, &r->ReferenceItems_offset, &r->ReferenceItems_size); - //;VGM_LOG("ACB: Synth[%i]: Type=%x, ReferenceItems={%x,%x}\n", Index, r->Type, r->ReferenceItems_offset, r->ReferenceItems_size); + /* CommandIndex: references SynthCommand[i], defines how index is used? */ } - ;VGM_LOG("acb: preload Synth done\n"); + utf_close(Table); return 1; fail: - VGM_LOG("ACB: failed Synth preload\n"); + VGM_LOG("acb: failed Synth preload\n"); + utf_close(Table); return 0; } static int load_acb_synth(acb_header* acb, uint16_t Index) { - int i, count; Synth_t* r; - Synth_t tmp; + int i, count; - - /* read Synth[Index] */ - if (acb->is_preload) { - if (!preload_acb_synth(acb)) goto fail; - if (Index > acb->Synth_rows) goto fail; - r = &acb->Synth[Index]; - } - else { - r = &tmp; - if (!open_utf_subtable(acb, &acb->SynthSf, &acb->SynthTable, "SynthTable", NULL, ACB_TABLE_BUFFER_SYNTH)) - goto fail; - - if (!utf_query_u8(acb->SynthTable, Index, "Type", &r->Type)) - goto fail; - if (!utf_query_data(acb->SynthTable, Index, "ReferenceItems", &r->ReferenceItems_offset, &r->ReferenceItems_size)) - goto fail; - //;VGM_LOG("ACB: Synth[%i]: Type=%x, ReferenceItems={%x,%x}\n", Index, r->Type, r->ReferenceItems_offset, r->ReferenceItems_size); - } + if (!preload_acb_synth(acb)) goto fail; + if (Index > acb->Synth_rows) goto fail; + r = &acb->Synth[Index]; + //;VGM_LOG("acb: Synth[%i]: Type=%x, ReferenceItems={%x,%x}\n", Index, r->Type, r->ReferenceItems_offset, r->ReferenceItems_size); acb->synth_depth++; /* sometimes 2 (ex. Yakuza 6) or even 3 (Street Fighter vs Tekken) */ if (acb->synth_depth > 3) { - VGM_LOG("ACB: Synth depth too high\n"); + VGM_LOG("acb: Synth depth too high\n"); goto fail; } //todo .CommandIndex > CommandTable - //todo .TrackValues > TrackTable? /* Cue.ReferenceType 2 uses Synth.Type, while 3 always sets it to 0 and uses Sequence.Type instead * Both look the same and probably affect which item in the ReferenceItems list is picked: @@ -536,14 +442,11 @@ static int load_acb_synth(acb_header* acb, uint16_t Index) { * Since we want to find all possible Waveforms that could match our id, we ignore Type and just parse all ReferenceItems. */ - if (!read_buffer(acb, r->ReferenceItems_offset, r->ReferenceItems_size, acb->SynthSf)) - goto fail; - count = r->ReferenceItems_size / 0x04; for (i = 0; i < count; i++) { - uint16_t item_type = get_u16be(acb->buf + i*0x04 + 0x00); - uint16_t item_index = get_u16be(acb->buf + i*0x04 + 0x02); - //;VGM_LOG("ACB: Synth.ReferenceItem: type=%x, index=%x\n", item_type, item_index); + uint16_t item_type = read_u16be(r->ReferenceItems_offset + i*0x04 + 0x00, acb->SynthSf); + uint16_t item_index = read_u16be(r->ReferenceItems_offset + i*0x04 + 0x02, acb->SynthSf); + //;VGM_LOG("acb: Synth.ReferenceItem: type=%x, index=%x\n", item_type, item_index); switch(item_type) { case 0x00: /* no reference */ @@ -569,7 +472,7 @@ static int load_acb_synth(acb_header* acb, uint16_t Index) { case 0x06: /* this seems to point to Synth but results don't make sense (rare, from Sonic Lost World) */ default: /* undefined/crashes AtomViewer */ - VGM_LOG("ACB: unknown Synth.ReferenceItem type %x at %x + %x\n", item_type, r->ReferenceItems_offset, r->ReferenceItems_size); + VGM_LOG("acb: unknown Synth.ReferenceItem type %x at %x + %x\n", item_type, r->ReferenceItems_offset, r->ReferenceItems_size); count = 0; /* force end without failing */ break; } @@ -579,7 +482,7 @@ static int load_acb_synth(acb_header* acb, uint16_t Index) { return 1; fail: - VGM_LOG("ACB: failed Synth %i\n", Index); + VGM_LOG("acb: failed Synth %i\n", Index); return 0; } @@ -591,13 +494,10 @@ static int load_acb_command_tlvs(acb_header* acb, STREAMFILE* sf, uint32_t Comma uint32_t pos = 0; uint32_t max_pos = Command_size; - if (!read_buffer(acb, Command_offset, Command_size, sf)) - goto fail; - /* read a (name)Command multiple TLV data */ while (pos < max_pos) { - tlv_code = get_u16be(acb->buf + pos + 0x00); - tlv_size = get_u8 (acb->buf + pos + 0x02); + tlv_code = read_u16be(Command_offset + pos + 0x00, sf); + tlv_size = read_u8 (Command_offset + pos + 0x02, sf); pos += 0x03; /* There are around 160 codes (some unused), with things like set volume, pan, stop, mute, and so on. @@ -607,13 +507,13 @@ static int load_acb_command_tlvs(acb_header* acb, STREAMFILE* sf, uint32_t Comma case 2000: /* noteOn */ case 2003: /* noteOnWithNo plus 16b (null?) [rare, ex. PES 2014] */ if (tlv_size < 0x04) { - VGM_LOG("ACB: TLV with unknown size\n"); + VGM_LOG("acb: TLV with unknown size\n"); break; } - tlv_type = get_u16be(acb->buf + pos + 0x00); /* ReferenceItem */ - tlv_index = get_u16be(acb->buf + pos + 0x02); - //;VGM_LOG("ACB: TLV at %x: type %x, index=%x\n", offset, tlv_type, tlv_index); + tlv_type = read_u16be(Command_offset + pos + 0x00, sf); /* ReferenceItem */ + tlv_index = read_u16be(Command_offset + pos + 0x02, sf); + //;VGM_LOG("acb: TLV at %x: type %x, index=%x\n", offset, tlv_type, tlv_index); /* same as Synth's ReferenceItem type? */ switch(tlv_type) { @@ -628,7 +528,7 @@ static int load_acb_command_tlvs(acb_header* acb, STREAMFILE* sf, uint32_t Comma break; default: - VGM_LOG("ACB: unknown TLV type %x at %x + %x\n", tlv_type, Command_offset + pos, tlv_size); + VGM_LOG("acb: unknown TLV type %x at %x + %x\n", tlv_type, Command_offset + pos, tlv_size); max_pos = 0; /* force end without failing */ break; } @@ -636,7 +536,7 @@ static int load_acb_command_tlvs(acb_header* acb, STREAMFILE* sf, uint32_t Comma case 2004: /* noteOnWithDuration */ /* same as the above plus extra field */ - //;VGM_LOG("ACB: TLV at %x: usable code %i?\n", offset-0x03, tlv_code); + //;VGM_LOG("acb: TLV at %x: usable code %i?\n", offset-0x03, tlv_code); break; case 33: /* mute */ @@ -651,7 +551,7 @@ static int load_acb_command_tlvs(acb_header* acb, STREAMFILE* sf, uint32_t Comma case 7100: /* startAction */ case 7101: /* stopAction */ /* may be needed? */ - //;VGM_LOG("ACB: TLV at %x: check code %i?\n", offset-0x03, tlv_code); + //;VGM_LOG("acb: TLV at %x: check code %i?\n", offset-0x03, tlv_code); break; case 0: /* no-op */ @@ -666,28 +566,27 @@ static int load_acb_command_tlvs(acb_header* acb, STREAMFILE* sf, uint32_t Comma return 1; fail: - VGM_LOG("ACB: failed Command TLVs\n"); + VGM_LOG("acb: failed Command TLVs\n"); return 0; } /*****************************************************************************/ static int preload_acb_trackcommand(acb_header* acb) { - utf_context* Table = acb->TrackCommandTable; + utf_context* Table = NULL; int* p_rows = &acb->TrackCommand_rows; int i, c_Command; - if (*p_rows) return 1; - /* load either TrackEvent (>=v1.28) or Command () <=v1.27 */ + /* load either TrackEvent (>=v1.28) or Command (<=v1.27) */ if (!open_utf_subtable(acb, &acb->TrackCommandSf, &Table, "TrackEventTable", p_rows, ACB_TABLE_BUFFER_TRACKCOMMAND)) { if (!open_utf_subtable(acb, &acb->TrackCommandSf, &Table, "CommandTable", p_rows, ACB_TABLE_BUFFER_TRACKCOMMAND)) goto fail; } if (!*p_rows) return 1; - ;VGM_LOG("acb: preload TrackEvent/Command=%i\n", *p_rows); + //;VGM_LOG("acb: preload TrackEvent/Command=%i\n", *p_rows); acb->TrackCommand = malloc(*p_rows * sizeof(TrackCommand_t)); if (!acb->TrackCommand) goto fail; @@ -698,46 +597,23 @@ static int preload_acb_trackcommand(acb_header* acb) { TrackCommand_t* r = &acb->TrackCommand[i]; utf_query_col_data(Table, i, c_Command, &r->Command_offset, &r->Command_size); - //;VGM_LOG("ACB: TrackEvent/Command[%i]: Command={%x,%x}\n", i, r->Command_offset, r->Command_size); } - ;VGM_LOG("acb: preload TrackEvent/Command done\n"); + utf_close(Table); return 1; fail: - VGM_LOG("ACB: failed TrackEvent/Command preload\n"); + VGM_LOG("acb: failed TrackEvent/Command preload\n"); + utf_close(Table); return 0; } static int load_acb_trackcommand(acb_header* acb, uint16_t Index) { TrackCommand_t* r; - TrackCommand_t tmp; - - - /* read TrackEvent/Command[Index] */ - if (acb->is_preload) { - if (!preload_acb_trackcommand(acb)) goto fail; - if (Index > acb->TrackCommand_rows) goto fail; - r = &acb->TrackCommand[Index]; - } - else { - r = &tmp; - if (acb->has_CommandTable) { /* <=v1.27 */ - if (!open_utf_subtable(acb, &acb->TrackCommandSf, &acb->TrackCommandTable, "CommandTable", NULL, ACB_TABLE_BUFFER_TRACKCOMMAND)) - goto fail; - } - else if (acb->has_TrackEventTable) { /* >=v1.28 */ - if (!open_utf_subtable(acb, &acb->TrackCommandSf, &acb->TrackCommandTable, "TrackEventTable", NULL, ACB_TABLE_BUFFER_TRACKCOMMAND)) - goto fail; - } - else { - VGM_LOG("ACB: unknown command table\n"); - goto fail; - } - if (!utf_query_data(acb->TrackCommandTable, Index, "Command", &r->Command_offset, &r->Command_size)) - goto fail; - //;VGM_LOG("ACB: TrackEvent/Command[%i]: Command={%x,%x}\n", Index, r->Command_offset, r->Command_size); - } + if (!preload_acb_trackcommand(acb)) goto fail; + if (Index > acb->TrackCommand_rows) goto fail; + r = &acb->TrackCommand[Index]; + //;VGM_LOG("acb: TrackEvent/Command[%i]: Command={%x,%x}\n", Index, r->Command_offset, r->Command_size); /* read Command's TLVs */ if (!load_acb_command_tlvs(acb, acb->TrackCommandSf, r->Command_offset, r->Command_size)) @@ -745,14 +621,14 @@ static int load_acb_trackcommand(acb_header* acb, uint16_t Index) { return 1; fail: - VGM_LOG("ACB: failed TrackCommand %i\n", Index); + VGM_LOG("acb: failed TrackCommand %i\n", Index); return 0; } /*****************************************************************************/ static int preload_acb_track(acb_header* acb) { - utf_context* Table = acb->TrackTable; + utf_context* Table = NULL; int* p_rows = &acb->Track_rows; int i, c_EventIndex; @@ -762,7 +638,7 @@ static int preload_acb_track(acb_header* acb) { goto fail; if (!*p_rows) return 1; - ;VGM_LOG("acb: preload Track=%i\n", *p_rows); + //;VGM_LOG("acb: preload Track=%i\n", *p_rows); acb->Track = malloc(*p_rows * sizeof(Track_t)); if (!acb->Track) goto fail; @@ -772,36 +648,26 @@ static int preload_acb_track(acb_header* acb) { for (i = 0; i < *p_rows; i++) { Track_t* r = &acb->Track[i]; - if (!utf_query_col_u16(Table, i, c_EventIndex, &r->EventIndex)) - goto fail; - //;VGM_LOG("ACB: Track[%i]: EventIndex=%i\n", i, r->EventIndex); + utf_query_col_u16(Table, i, c_EventIndex, &r->EventIndex); + /* TargetType: changes ACB target? */ + /* CommandIndex: references TrackCommand[i], defines how index is used? */ } - ;VGM_LOG("acb: preload Track done\n"); + utf_close(Table); return 1; fail: - VGM_LOG("ACB: failed Track preload\n"); + VGM_LOG("acb: failed Track preload\n"); + utf_close(Table); return 0; } static int load_acb_track(acb_header* acb, uint16_t Index) { Track_t* r; - Track_t tmp; - - /* read Track[Index] */ - if (acb->is_preload) { - if (!preload_acb_track(acb)) goto fail; - if (Index > acb->Track_rows) goto fail; - r = &acb->Track[Index]; - } - else { - r = &tmp; - if (!open_utf_subtable(acb, &acb->TrackSf, &acb->TrackTable, "TrackTable", NULL, ACB_TABLE_BUFFER_TRACK)) - goto fail; - if (!utf_query_u16(acb->TrackTable, Index, "EventIndex", &r->EventIndex)) - goto fail; - } + if (!preload_acb_track(acb)) goto fail; + if (Index > acb->Track_rows) goto fail; + r = &acb->Track[Index]; + //;VGM_LOG("acb: Track[%i]: EventIndex=%i\n", Index, r->EventIndex); //todo CommandIndex? @@ -814,16 +680,16 @@ static int load_acb_track(acb_header* acb, uint16_t Index) { return 1; fail: - VGM_LOG("ACB: failed Track %i\n", Index); + VGM_LOG("acb: failed Track %i\n", Index); return 0; } /*****************************************************************************/ static int preload_acb_sequence(acb_header* acb) { - utf_context* Table = acb->SequenceTable; + utf_context* Table = NULL; int* p_rows = &acb->Sequence_rows; - int i, c_NumTracks, c_TrackIndex, c_ActionTrackStartIndex, c_NumActionTracks, c_TrackValues, c_Type; + int i, c_NumTracks, c_TrackIndex, c_Type; if (*p_rows) return 1; @@ -831,16 +697,15 @@ static int preload_acb_sequence(acb_header* acb) { goto fail; if (!*p_rows) return 1; - ;VGM_LOG("acb: preload Sequence=%i\n", *p_rows); + //;VGM_LOG("acb: preload Sequence=%i\n", *p_rows); acb->Sequence = malloc(*p_rows * sizeof(Sequence_t)); if (!acb->Sequence) goto fail; c_NumTracks = utf_get_column(Table, "NumTracks"); c_TrackIndex = utf_get_column(Table, "TrackIndex"); - c_ActionTrackStartIndex = utf_get_column(Table, "ActionTrackStartIndex"); - c_NumActionTracks = utf_get_column(Table, "NumActionTracks"); - c_TrackValues = utf_get_column(Table, "TrackValues"); + //c_ActionTrackStartIndex = utf_get_column(Table, "ActionTrackStartIndex"); + //c_NumActionTracks = utf_get_column(Table, "NumActionTracks"); c_Type = utf_get_column(Table, "Type"); for (i = 0; i < *p_rows; i++) { @@ -848,100 +713,83 @@ static int preload_acb_sequence(acb_header* acb) { utf_query_col_u16(Table, i, c_NumTracks, &r->NumTracks); utf_query_col_data(Table, i, c_TrackIndex, &r->TrackIndex_offset, &r->TrackIndex_size); - utf_query_col_u16(Table, i, c_ActionTrackStartIndex, &r->ActionTrackStartIndex); - utf_query_col_u16(Table, i, c_NumActionTracks, &r->NumActionTracks); - utf_query_col_data(Table, i, c_TrackValues, &r->TrackValues_offset, &r->TrackValues_size); + //utf_query_col_u16(Table, i, c_ActionTrackStartIndex, &r->ActionTrackStartIndex); + //utf_query_col_u16(Table, i, c_NumActionTracks, &r->NumActionTracks); utf_query_col_u8(Table, i, c_Type, &r->Type); - //;VGM_LOG("ACB: Sequence[%i]: NumTracks=%i, TrackIndex={%x, %x}, TrackIndex={%x, %x}, Type=%x\n", i, r->NumTracks, r->TrackIndex_offset, r->TrackIndex_size, r->TrackValues_offset, r->TrackValues_size, r->Type); + /* CommandIndex: references SequenceCommand[i], defines how index is used? */ } - ;VGM_LOG("acb: preload Sequence done\n"); + utf_close(Table); return 1; fail: - VGM_LOG("ACB: failed Sequence preload\n"); + VGM_LOG("acb: failed Sequence preload\n"); + utf_close(Table); return 0; } static int load_acb_sequence(acb_header* acb, uint16_t Index) { - int i; Sequence_t* r; - Sequence_t tmp; + int i; + if (!preload_acb_sequence(acb)) goto fail; + if (Index > acb->Sequence_rows) goto fail; + r = &acb->Sequence[Index]; + //;VGM_LOG("acb: Sequence[%i]: NumTracks=%i, TrackIndex={%x, %x}, Type=%x\n", Index, r->NumTracks, r->TrackIndex_offset, r->TrackIndex_size, r->Type); - /* read Sequence[Index] */ - if (acb->is_preload) { - if (!preload_acb_sequence(acb)) goto fail; - if (Index > acb->Sequence_rows) goto fail; - r = &acb->Sequence[Index]; - } - else { - r = &tmp; - if (!open_utf_subtable(acb, &acb->SequenceSf, &acb->SequenceTable, "SequenceTable", NULL, ACB_TABLE_BUFFER_SEQUENCE)) - goto fail; - - if (!utf_query_u16(acb->SequenceTable, Index, "NumTracks", &r->NumTracks)) - goto fail; - if (!utf_query_data(acb->SequenceTable, Index, "TrackIndex", &r->TrackIndex_offset, &r->TrackIndex_size)) - goto fail; - } - - //todo .CommandIndex > SequenceCommand? - // most unknown types can be found in Ultra Despair Girls (PC) + //TODO most unknown types can be found in Ultra Despair Girls (PC) acb->sequence_depth++; if (acb->sequence_depth > 3) { - VGM_LOG("ACB: Sequence depth too high\n"); + VGM_LOG("acb: Sequence depth too high\n"); goto fail; /* max Sequence > Sequence > Sequence > Synth > Waveform (ex. Yakuza 6) */ } - - /* read Tracks inside Sequence */ +#if 0 + /* reference to ActionTrack[i..] */ if (r->NumActionTracks) { VGM_LOG_ONCE("ACB: ignored ActionTrack[%i~%i]\n", r->ActionTrackStartIndex, r->NumActionTracks); } - else { - if (r->NumTracks * 0x02 > r->TrackIndex_size) { /* padding may exist */ - VGM_LOG("ACB: wrong Sequence.TrackIndex size\n"); - goto fail; - } +#endif - switch(r->Type) { - case 0: /* common */ - if (!read_buffer(acb, r->TrackIndex_offset, r->TrackIndex_size, acb->SequenceSf)) + if (r->NumTracks * 0x02 > r->TrackIndex_size) { /* padding may exist */ + VGM_LOG("acb: wrong Sequence.TrackIndex size\n"); + goto fail; + } + + /* read Tracks inside Sequence */ + switch(r->Type) { + /* types affect which item in the TrackIndex list is picked (see load_acb_synth) */ + case 0: /* polyphonic (TrackIndex only) */ + case 1: /* sequential (TrackIndex only) */ + case 3: /* random (TrackIndex + TrackValues = int percent) */ + case 4: /* random no repeat (TrackIndex + TrackValues = int percent) */ + default: + for (i = 0; i < r->NumTracks; i++) { + int16_t TrackIndex_index = read_s16be(r->TrackIndex_offset + i*0x02, acb->SequenceSf); + + if (!load_acb_track(acb, TrackIndex_index)) goto fail; + } + break; - for (i = 0; i < r->NumTracks; i++) { - int16_t TrackIndex_index = get_s16be(acb->buf + i*0x02); - - if (!load_acb_track(acb, TrackIndex_index)) - goto fail; - } - break; - - case 1: /* TrackIndex only, similar to 0? (rare) */ - VGM_LOG_ONCE("ACB: unknown Sequence.Type=%x\n", r->Type); - break; - case 3: /* TrackIndex + TrackValues */ - case 4: /* same */ - default: - VGM_LOG_ONCE("ACB: unknown Sequence.Type=%x\n", r->Type); - break; - } + //default: + // VGM_LOG_ONCE("ACB: unknown Sequence.Type=%x\n", r->Type); + // break; } acb->sequence_depth--; return 1; fail: - VGM_LOG("ACB: failed Sequence %i\n", Index); + VGM_LOG("acb: failed Sequence %i\n", Index); return 0; } /*****************************************************************************/ static int preload_acb_block(acb_header* acb) { - utf_context* Table = acb->BlockTable; + utf_context* Table = NULL; int* p_rows = &acb->Block_rows; int i, c_NumTracks, c_TrackIndex; @@ -951,7 +799,7 @@ static int preload_acb_block(acb_header* acb) { goto fail; if (!*p_rows) return 1; - ;VGM_LOG("acb: preload Block=%i\n", *p_rows); + //;VGM_LOG("acb: preload Block=%i\n", *p_rows); acb->Block = malloc(*p_rows * sizeof(Block_t)); if (!acb->Block) goto fail; @@ -964,52 +812,34 @@ static int preload_acb_block(acb_header* acb) { utf_query_col_u16(Table, i, c_NumTracks, &r->NumTracks); utf_query_col_data(Table, i, c_TrackIndex, &r->TrackIndex_offset, &r->TrackIndex_size); - //;VGM_LOG("ACB: Block[%i]: NumTracks=%i, TrackIndex={%x, %x}\n", i, r->NumTracks, r->TrackIndex_offset, r->TrackIndex_size); + //todo .ActionTrackStartIndex/NumActionTracks > ? } - ;VGM_LOG("acb: preload Block done\n"); + utf_close(Table); return 1; fail: - VGM_LOG("ACB: failed Block preload\n"); + VGM_LOG("acb: failed Block preload\n"); + utf_close(Table); return 0; } static int load_acb_block(acb_header* acb, uint16_t Index) { - int i; Block_t* r; - Block_t tmp; + int i; - - /* read Block[Index] */ - if (acb->is_preload) { - if (!preload_acb_block(acb)) goto fail; - if (Index > acb->Block_rows) goto fail; - r = &acb->Block[Index]; - } - else { - r = &tmp; - if (!open_utf_subtable(acb, &acb->BlockSf, &acb->BlockTable, "BlockTable", NULL, ACB_TABLE_BUFFER_BLOCK)) - goto fail; - - if (!utf_query_u16(acb->BlockTable, Index, "NumTracks", &r->NumTracks)) - goto fail; - if (!utf_query_data(acb->BlockTable, Index, "TrackIndex", &r->TrackIndex_offset, &r->TrackIndex_size)) - goto fail; - } + if (!preload_acb_block(acb)) goto fail; + if (Index > acb->Block_rows) goto fail; + r = &acb->Block[Index]; + //;VGM_LOG("acb: Block[%i]: NumTracks=%i, TrackIndex={%x, %x}\n", Index, r->NumTracks, r->TrackIndex_offset, r->TrackIndex_size); if (r->NumTracks * 0x02 > r->TrackIndex_size) { /* padding may exist */ - VGM_LOG("ACB: wrong Block.TrackIndex size\n"); + VGM_LOG("acb: wrong Block.TrackIndex size\n"); goto fail; } - //todo .ActionTrackStartIndex/NumActionTracks > ? - - if (!read_buffer(acb, r->TrackIndex_offset, r->TrackIndex_size, acb->BlockSf)) - goto fail; - /* read Tracks inside Block */ for (i = 0; i < r->NumTracks; i++) { - int16_t TrackIndex_index = get_s16be(acb->buf + i*0x02); + int16_t TrackIndex_index = read_s16be(r->TrackIndex_offset + i*0x02, acb->BlockSf); if (!load_acb_track(acb, TrackIndex_index)) goto fail; @@ -1017,14 +847,14 @@ static int load_acb_block(acb_header* acb, uint16_t Index) { return 1; fail: - VGM_LOG("ACB: failed Block %i\n", Index); + VGM_LOG("acb: failed Block %i\n", Index); return 0; } /*****************************************************************************/ static int preload_acb_blocksequence(acb_header* acb) { - utf_context* Table = acb->BlockSequenceTable; + utf_context* Table = NULL; int* p_rows = &acb->BlockSequence_rows; int i, c_NumTracks, c_TrackIndex, c_NumBlocks, c_BlockIndex; @@ -1034,7 +864,7 @@ static int preload_acb_blocksequence(acb_header* acb) { goto fail; if (!*p_rows) return 1; - ;VGM_LOG("acb: preload BlockSequence=%i\n", *p_rows); + //;VGM_LOG("acb: preload BlockSequence=%i\n", *p_rows); acb->BlockSequence = malloc(*p_rows * sizeof(BlockSequence_t)); if (!acb->BlockSequence) goto fail; @@ -1053,69 +883,44 @@ static int preload_acb_blocksequence(acb_header* acb) { utf_query_col_data(Table, i, c_BlockIndex, &r->BlockIndex_offset, &r->BlockIndex_size); } - ;VGM_LOG("acb: preload BlockSequence done\n"); + utf_close(Table); return 1; fail: - VGM_LOG("ACB: failed BlockSequence preload\n"); + VGM_LOG("acb: failed BlockSequence preload\n"); + utf_close(Table); return 0; } static int load_acb_blocksequence(acb_header* acb, uint16_t Index) { - int i; BlockSequence_t* r; - BlockSequence_t tmp; - - - /* read BlockSequence[Index] */ - if (acb->is_preload) { - if (!preload_acb_blocksequence(acb)) goto fail; - if (Index > acb->BlockSequence_rows) goto fail; - r = &acb->BlockSequence[Index]; - } - else { - r = &tmp; - if (!open_utf_subtable(acb, &acb->BlockSequenceSf, &acb->BlockSequenceTable, "BlockSequenceTable", NULL, ACB_TABLE_BUFFER_BLOCKSEQUENCE)) - goto fail; - - if (!utf_query_u16(acb->BlockSequenceTable, Index, "NumTracks", &r->NumTracks)) - goto fail; - if (!utf_query_data(acb->BlockSequenceTable, Index, "TrackIndex", &r->TrackIndex_offset, &r->TrackIndex_size)) - goto fail; - if (!utf_query_u16(acb->BlockSequenceTable, Index, "NumBlocks", &r->NumBlocks)) - goto fail; - if (!utf_query_data(acb->BlockSequenceTable, Index, "BlockIndex", &r->BlockIndex_offset, &r->BlockIndex_size)) - goto fail; - //;VGM_LOG("ACB: BlockSequence[%i]: NumTracks=%i, TrackIndex={%x, %x}, NumBlocks=%i, BlockIndex={%x, %x}\n", Index, r->NumTracks, r->TrackIndex_offset,TrackIndex_size, r->NumBlocks, r->BlockIndex_offset, r->BlockIndex_size); - } + int i; + if (!preload_acb_blocksequence(acb)) goto fail; + if (Index > acb->BlockSequence_rows) goto fail; + r = &acb->BlockSequence[Index]; + //;VGM_LOG("acb: BlockSequence[%i]: NumTracks=%i, TrackIndex={%x, %x}, NumBlocks=%i, BlockIndex={%x, %x}\n", Index, r->NumTracks, r->TrackIndex_offset,r->TrackIndex_size, r->NumBlocks, r->BlockIndex_offset, r->BlockIndex_size); if (r->NumTracks * 0x02 > r->TrackIndex_size) { /* padding may exist */ - VGM_LOG("ACB: wrong BlockSequence.TrackIndex size\n"); + VGM_LOG("acb: wrong BlockSequence.TrackIndex size\n"); goto fail; } - if (!read_buffer(acb, r->TrackIndex_offset, r->TrackIndex_size, acb->BlockSequenceSf)) - goto fail; - /* read Tracks inside BlockSequence */ for (i = 0; i < r->NumTracks; i++) { - int16_t TrackIndex_index = get_s16be(acb->buf + i*0x02); + int16_t TrackIndex_index = read_s16be(r->TrackIndex_offset + i*0x02, acb->BlockSequenceSf); if (!load_acb_track(acb, TrackIndex_index)) goto fail; } if (r->NumBlocks * 0x02 > r->BlockIndex_size) { - VGM_LOG("ACB: wrong BlockSequence.BlockIndex size\n"); + VGM_LOG("acb: wrong BlockSequence.BlockIndex size\n"); goto fail; } - if (!read_buffer(acb, r->BlockIndex_offset, r->BlockIndex_size, acb->BlockSequenceSf)) - goto fail; - /* read Blocks inside BlockSequence */ for (i = 0; i < r->NumBlocks; i++) { - int16_t BlockIndex_index = get_s16be(acb->buf + i*0x02); + int16_t BlockIndex_index = read_s16be(r->BlockIndex_offset + i*0x02, acb->BlockSequenceSf); if (!load_acb_block(acb, BlockIndex_index)) goto fail; @@ -1123,14 +928,14 @@ static int load_acb_blocksequence(acb_header* acb, uint16_t Index) { return 1; fail: - VGM_LOG("ACB: failed BlockSequence %i\n", Index); + VGM_LOG("acb: failed BlockSequence %i\n", Index); return 0; } /*****************************************************************************/ static int preload_acb_cue(acb_header* acb) { - utf_context* Table = acb->CueTable; + utf_context* Table = NULL; int* p_rows = &acb->Cue_rows; int i, c_ReferenceType, c_ReferenceIndex; @@ -1140,7 +945,7 @@ static int preload_acb_cue(acb_header* acb) { goto fail; if (!*p_rows) return 1; - ;VGM_LOG("acb: preload Cue=%i\n", *p_rows); + //;VGM_LOG("acb: preload Cue=%i\n", *p_rows); acb->Cue = malloc(*p_rows * sizeof(Cue_t)); if (!acb->Cue) goto fail; @@ -1153,35 +958,24 @@ static int preload_acb_cue(acb_header* acb) { utf_query_col_u8(Table, i, c_ReferenceType, &r->ReferenceType); utf_query_col_u16(Table, i, c_ReferenceIndex, &r->ReferenceIndex); - //;VGM_LOG("ACB: Cue[%i]: ReferenceType=%i, ReferenceIndex=%i\n", i, r->ReferenceType, r->ReferenceIndex); } - ;VGM_LOG("acb: preload Cue done\n"); + utf_close(Table); return 1; fail: - VGM_LOG("ACB: failed Cue preload\n"); + VGM_LOG("acb: failed Cue preload\n"); + utf_close(Table); return 0; } static int load_acb_cue(acb_header* acb, uint16_t Index) { Cue_t* r; - Cue_t tmp; /* read Cue[Index] */ - if (acb->is_preload) { - if (!preload_acb_cue(acb)) goto fail; - if (Index > acb->Cue_rows) goto fail; - r = &acb->Cue[Index]; - } - else { - if (!open_utf_subtable(acb, &acb->CueSf, &acb->CueTable, "CueTable", NULL, ACB_TABLE_BUFFER_CUE)) - goto fail; - r = &tmp; - if (!utf_query_u8(acb->CueTable, Index, "ReferenceType", &r->ReferenceType)) - goto fail; - if (!utf_query_u16(acb->CueTable, Index, "ReferenceIndex", &r->ReferenceIndex)) - goto fail; - } + if (!preload_acb_cue(acb)) goto fail; + if (Index > acb->Cue_rows) goto fail; + r = &acb->Cue[Index]; + //;VGM_LOG("acb: Cue[%i]: ReferenceType=%i, ReferenceIndex=%i\n", Index, r->ReferenceType, r->ReferenceIndex); /* usually older games use older references but not necessarily */ @@ -1223,25 +1017,24 @@ static int load_acb_cue(acb_header* acb, uint16_t Index) { return 1; fail: - VGM_LOG("ACB: failed Cue %i\n", Index); + VGM_LOG("acb: failed Cue %i\n", Index); return 0; } /*****************************************************************************/ static int preload_acb_cuename(acb_header* acb) { - utf_context* Table = acb->CueNameTable; + utf_context* Table = acb->CueNames; int* p_rows = &acb->CueName_rows; int i, c_CueIndex, c_CueName; - if (*p_rows) return 1; if (!open_utf_subtable(acb, &acb->CueNameSf, &Table, "CueNameTable", p_rows, ACB_TABLE_BUFFER_CUENAME)) goto fail; if (!*p_rows) return 1; - ;VGM_LOG("acb: preload CueName=%i\n", *p_rows); + //;VGM_LOG("acb: preload CueName=%i\n", *p_rows); acb->CueName = malloc(*p_rows * sizeof(CueName_t)); if (!acb->CueName) goto fail; @@ -1254,36 +1047,22 @@ static int preload_acb_cuename(acb_header* acb) { utf_query_col_u16(Table, i, c_CueIndex, &r->CueIndex); utf_query_col_string(Table, i, c_CueName, &r->CueName); - //;VGM_LOG("ACB: CueName[%i]: CueIndex=%i, CueName=%s\n", i, r->CueIndex, r->CueName); } - ;VGM_LOG("acb: preload CueName done\n"); + //utf_close(Table); /* keep this table around since we need CueName pointers */ return 1; fail: - VGM_LOG("ACB: failed CueName preload\n"); + VGM_LOG("acb: failed CueName preload\n"); return 0; } static int load_acb_cuename(acb_header* acb, uint16_t Index) { CueName_t* r; - CueName_t tmp; - - /* read CueName[Index] */ - if (acb->is_preload) { - if (!preload_acb_cuename(acb)) goto fail; - if (Index > acb->CueName_rows) goto fail; - r = &acb->CueName[Index]; - } - else { - if (!open_utf_subtable(acb, &acb->CueNameSf, &acb->CueNameTable, "CueNameTable", NULL, ACB_TABLE_BUFFER_CUENAME)) - goto fail; - r = &tmp; - if (!utf_query_u16(acb->CueNameTable, Index, "CueIndex", &r->CueIndex)) - goto fail; - if (!utf_query_string(acb->CueNameTable, Index, "CueName", &r->CueName)) - goto fail; - } + if (!preload_acb_cuename(acb)) goto fail; + if (Index > acb->CueName_rows) goto fail; + r = &acb->CueName[Index]; + //;VGM_LOG("acb: CueName[%i]: CueIndex=%i, CueName=%s\n", Index, r->CueIndex, r->CueName); /* save as will be needed if references waveform */ acb->cuename_index = Index; @@ -1294,49 +1073,49 @@ static int load_acb_cuename(acb_header* acb, uint16_t Index) { return 1; fail: - VGM_LOG("ACB: failed CueName %i\n", Index); + VGM_LOG("acb: failed CueName %i\n", Index); return 0; } /*****************************************************************************/ +/* Normally games load a .acb + .awb, and asks the .acb to play a cue by name or index. + * Since we only care for actual waves, to get its name we need to find which cue uses our wave. + * Multiple cues can use the same wave (meaning multiple names), and one cue may use multiple waves. + * There is no easy way to map cue name <> wave name so basically we parse the whole thing. + * + * .acb are created in CRI Atom Craft, where user defines N Cues with CueName each, then link somehow + * to a Waveform (.awb=streamed or memory .acb=internal, data 'material' encoded in some format), + * depending on reference types. Typical links are: + * - CueName > Cue > Waveform (type 1) + * - CueName > Cue > Synth > Waveform (type 2) + * - CueName > Cue > Sequence > Track > Command > Synth > Waveform (type 3, <=v1.27) + * - CueName > Cue > Sequence > Track > Command > Synth > Synth > Waveform (type 3, <=v1.27) + * - CueName > Cue > Sequence > Track > TrackEvent > Command > Synth > Waveform (type 3, >=v1.28) + * - CueName > Cue > Sequence > Track > TrackEvent > Command > Synth > Synth > Waveform (type 3, >=v1.28) + * - CueName > Cue > Sequence > Track > TrackEvent > Command > Sequence > (...) > Synth > Waveform (type 3, >=v1.28) + * - CueName > Cue > Block > Track > Command > Synth > Synth > Waveform (type 8) + * - others should be possible + * Atom Craft may only target certain .acb versions so some links are later removed + * Not all cues to point to Waveforms, some are just config events/commands. + * .acb link to .awb by name (loaded manually), though they have a checksum/hash/header to validate. + * + * .acb can contain info for multiple .awb, that are loaded sequentially and assigned "port numbers" (0 to N). + * Both Wave ID and port number must be passed externally to find appropriate song name. + * + * To improve performance we pre-read each table objects's useful fields. Extra complex files may include +8000 objects, + * per table, meaning it uses a decent chunk of memory, but having to re-read with streamfiles is much slower. + */ + void load_acb_wave_name(STREAMFILE* sf, VGMSTREAM* vgmstream, int waveid, int port, int is_memory) { acb_header acb = {0}; - int i, CueName_rows; + int i; if (!sf || !vgmstream || waveid < 0) return; - /* Normally games load a .acb + .awb, and asks the .acb to play a cue by name or index. - * Since we only care for actual waves, to get its name we need to find which cue uses our wave. - * Multiple cues can use the same wave (meaning multiple names), and one cue may use multiple waves. - * There is no easy way to map cue name <> wave name so basically we parse the whole thing. - * - * .acb are created in CRI Atom Craft, where user defines N Cues with CueName each, then link somehow - * to a Waveform (.awb=streamed or memory .acb=internal, data 'material' encoded in some format), - * depending on reference types. Typical links are: - * - CueName > Cue > Waveform (type 1) - * - CueName > Cue > Synth > Waveform (type 2) - * - CueName > Cue > Sequence > Track > Command > Synth > Waveform (type 3, <=v1.27) - * - CueName > Cue > Sequence > Track > Command > Synth > Synth > Waveform (type 3, <=v1.27) - * - CueName > Cue > Sequence > Track > TrackEvent > Command > Synth > Waveform (type 3, >=v1.28) - * - CueName > Cue > Sequence > Track > TrackEvent > Command > Synth > Synth > Waveform (type 3, >=v1.28) - * - CueName > Cue > Sequence > Track > TrackEvent > Command > Sequence > (...) > Synth > Waveform (type 3, >=v1.28) - * - CueName > Cue > Block > Track > Command > Synth > Synth > Waveform (type 8) - * - others should be possible - * Atom Craft may only target certain .acb versions so some links are later removed - * Not all cues to point to Waveforms, some are just config events/commands. - * .acb link to .awb by name (loaded manually), though they have a checksum/hash/header to validate. - * - * .acb can contain info for multiple .awb, that are loaded sequentially and assigned "port numbers" (0 to N). - * Both Wave ID and port number must be passed externally to find appropriate song name. - * - * To improve performance we pre-read each table objects's useful fields. Extra complex files may include +8000 objects, - * per table, meaning it uses a decent chunk of memory, but having to re-read with streamfiles is much slower. - */ - - //;VGM_LOG("ACB: find waveid=%i, port=%i\n", waveid, port); + //;VGM_LOG("acb: find waveid=%i, port=%i\n", waveid, port); acb.acbFile = sf; @@ -1347,19 +1126,9 @@ void load_acb_wave_name(STREAMFILE* sf, VGMSTREAM* vgmstream, int waveid, int po acb.target_port = port; acb.is_memory = is_memory; - -#ifdef ACB_PRELOAD - acb.is_preload = 1; -#else - acb.has_TrackEventTable = utf_query_data(acb.Header, 0, "TrackEventTable", NULL,NULL); - acb.has_CommandTable = utf_query_data(acb.Header, 0, "CommandTable", NULL,NULL); -#endif - - //todo preload cuename table /* read all possible cue names and find which waveids are referenced by it */ - if (!open_utf_subtable(&acb, &acb.TempSf, &acb.TempTable, "CueNameTable", &CueName_rows, ACB_TABLE_BUFFER_CUENAME)) - goto fail; - for (i = 0; i < CueName_rows; i++) { + preload_acb_cuename(&acb); + for (i = 0; i < acb.CueName_rows; i++) { if (!load_acb_cuename(&acb, i)) goto fail; } @@ -1370,21 +1139,10 @@ void load_acb_wave_name(STREAMFILE* sf, VGMSTREAM* vgmstream, int waveid, int po vgmstream->stream_name[STREAM_NAME_SIZE - 1] = '\0'; } + /* done */ fail: utf_close(acb.Header); - - utf_close(acb.TempTable); - close_streamfile(acb.TempSf); - - utf_close(acb.CueNameTable); - utf_close(acb.CueTable); - utf_close(acb.BlockSequenceTable); - utf_close(acb.BlockTable); - utf_close(acb.SequenceTable); - utf_close(acb.TrackTable); - utf_close(acb.TrackCommandTable); - utf_close(acb.SynthTable); - utf_close(acb.WaveformTable); + utf_close(acb.CueNames); close_streamfile(acb.CueNameSf); close_streamfile(acb.CueSf); @@ -1396,8 +1154,6 @@ fail: close_streamfile(acb.SynthSf); close_streamfile(acb.WaveformSf); - free(acb.buf); - free(acb.CueName); free(acb.Cue); free(acb.BlockSequence); diff --git a/Frameworks/vgmstream/vgmstream/src/meta/adx.c b/Frameworks/vgmstream/vgmstream/src/meta/adx.c index 62937b736..418bce144 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/adx.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/adx.c @@ -11,7 +11,7 @@ #define ADX_KEY_MAX_TEST_FRAMES 32768 #define ADX_KEY_TEST_BUFFER_SIZE 0x8000 -static int find_adx_key(STREAMFILE *sf, uint8_t type, uint16_t *xor_start, uint16_t *xor_mult, uint16_t *xor_add, uint16_t subkey); +static int find_adx_key(STREAMFILE* sf, uint8_t type, uint16_t* xor_start, uint16_t* xor_mult, uint16_t* xor_add, uint16_t subkey); VGMSTREAM* init_vgmstream_adx(STREAMFILE* sf) { return init_vgmstream_adx_subkey(sf, 0); @@ -34,14 +34,14 @@ VGMSTREAM* init_vgmstream_adx_subkey(STREAMFILE* sf, uint16_t subkey) { /* checks*/ + if (read_u16be(0x00,sf) != 0x8000) + goto fail; + /* .adx: standard * .adp: Headhunter (DC) */ if (!check_extensions(sf,"adx,adp")) goto fail; - if (read_u16be(0x00,sf) != 0x8000) - goto fail; - start_offset = read_u16be(0x02,sf) + 0x04; if (read_u16be(start_offset - 0x06,sf) != 0x2863 || /* "(c" */ read_u32be(start_offset - 0x04,sf) != 0x29435249) /* ")CRI" */ @@ -79,18 +79,19 @@ VGMSTREAM* init_vgmstream_adx_subkey(STREAMFILE* sf, uint16_t subkey) { /* encryption */ if (version == 0x0408) { + if (find_adx_key(sf, 8, &xor_start, &xor_mult, &xor_add, 0)) { - coding_type = coding_CRI_ADX_enc_8; - version = 0x0400; + vgm_logi("ADX: decryption keystring not found\n"); } - vgm_asserti(version != 0x0400, "ADX: decryption keystring not found\n"); + coding_type = coding_CRI_ADX_enc_8; + version = 0x0400; } else if (version == 0x0409) { if (find_adx_key(sf, 9, &xor_start, &xor_mult, &xor_add, subkey)) { - coding_type = coding_CRI_ADX_enc_9; - version = 0x0400; + vgm_logi("ADX: decryption keycode not found\n"); } - vgm_asserti(version != 0x0400, "ADX: decryption keycode not found\n"); + coding_type = coding_CRI_ADX_enc_9; + version = 0x0400; } /* version + extra data */ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ao.c b/Frameworks/vgmstream/vgmstream/src/meta/ao.c index 5c151ff9e..44dfae54c 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ao.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ao.c @@ -2,18 +2,17 @@ #include "../coding/coding.h" /* .AO - from AlphaOgg lib [Cloudphobia (PC), GEO ~The Sword Millennia~ Kasumi no Tani no Kaibutsu (PC)] */ -VGMSTREAM* init_vgmstream_ao(STREAMFILE *sf) { +VGMSTREAM* init_vgmstream_ao(STREAMFILE* sf) { VGMSTREAM* vgmstream = NULL; off_t start_offset; /* checks */ - if (!check_extensions(sf,"ao")) - goto fail; if (!is_id64be(0x00,sf, "ALPHAOGG")) goto fail; + if (!check_extensions(sf,"ao")) + goto fail; -#ifdef VGM_USE_VORBIS { ogg_vorbis_meta_info_t ovmi = {0}; int sample_rate = read_u32le(0xF0, sf); /* Ogg header */ @@ -29,9 +28,6 @@ VGMSTREAM* init_vgmstream_ao(STREAMFILE *sf) { start_offset = 0xc8; vgmstream = init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi); } -#else - goto fail; -#endif return vgmstream; fail: diff --git a/Frameworks/vgmstream/vgmstream/src/meta/atsl.c b/Frameworks/vgmstream/vgmstream/src/meta/atsl.c index fb12d0fae..c1f272935 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/atsl.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/atsl.c @@ -10,7 +10,7 @@ VGMSTREAM* init_vgmstream_atsl(STREAMFILE* sf) { int type, big_endian = 0, entries; uint32_t subfile_offset = 0, subfile_size = 0, header_size, entry_size; - VGMSTREAM* (*init_vgmstream)(STREAMFILE* sf) = NULL; + init_vgmstream_t init_vgmstream = NULL; const char* fake_ext; @@ -47,7 +47,6 @@ VGMSTREAM* init_vgmstream_atsl(STREAMFILE* sf) { type = read_u16le(0x0c, sf); switch(type) { -#ifdef VGM_USE_VORBIS case 0x0100: /* KOVS */ init_vgmstream = init_vgmstream_ogg_vorbis; fake_ext = "kvs"; @@ -58,7 +57,6 @@ VGMSTREAM* init_vgmstream_atsl(STREAMFILE* sf) { fake_ext = "kvs"; entry_size = 0x3c; break; -#endif case 0x0200: /* ATRAC3 */ init_vgmstream = init_vgmstream_riff; fake_ext = "at3"; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/awb.c b/Frameworks/vgmstream/vgmstream/src/meta/awb.c index 7cff3061a..177ca3664 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/awb.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/awb.c @@ -87,7 +87,7 @@ VGMSTREAM* init_vgmstream_awb_memory(STREAMFILE* sf, STREAMFILE* sf_acb) { VGMSTREAM* (*init_vgmstream_subkey)(STREAMFILE* sf, uint16_t subkey) = NULL; const char* extension = NULL; - if (read_u16be(subfile_offset, sf) == 0x8000) { /* (type 0=ADX) */ + if (read_u16be(subfile_offset, sf) == 0x8000) { /* (type 0=ADX, also 3?) */ init_vgmstream_subkey = init_vgmstream_adx_subkey; /* Okami HD (PS4) */ extension = "adx"; } @@ -99,7 +99,7 @@ VGMSTREAM* init_vgmstream_awb_memory(STREAMFILE* sf, STREAMFILE* sf_acb) { init_vgmstream = init_vgmstream_vag; /* Ukiyo no Roushi (Vita) */ extension = "vag"; } - else if (is_id32be(subfile_offset,sf, "RIFF")) { /* (type 8=ATRAC3, 11=ATRAC9) */ + else if (is_id32be(subfile_offset,sf, "RIFF")) { /* (type 8=ATRAC3, 11=ATRAC9, also 18=ATRAC9?) */ init_vgmstream = init_vgmstream_riff; /* Ukiyo no Roushi (Vita) */ extension = "wav"; subfile_size = read_u32le(subfile_offset + 0x04,sf) + 0x08; /* padded size, use RIFF's */ @@ -111,7 +111,7 @@ VGMSTREAM* init_vgmstream_awb_memory(STREAMFILE* sf, STREAMFILE* sf_acb) { else if (read_u32be(subfile_offset + 0x08,sf) >= 8000 && read_u32be(subfile_offset + 0x08,sf) <= 48000 && read_u16be(subfile_offset + 0x0e,sf) == 0 && read_u32be(subfile_offset + 0x18,sf) == 2 && - read_u32be(subfile_offset + 0x50,sf) == 0) { /* (type 13=DSP), probably should call some check function */ + read_u32be(subfile_offset + 0x50,sf) == 0) { /* (type 13=DSP, also 4=Wii?, 5=NDS?), probably should call some check function */ init_vgmstream = init_vgmstream_ngc_dsp_std; /* Sonic: Lost World (WiiU) */ extension = "dsp"; } @@ -125,7 +125,7 @@ VGMSTREAM* init_vgmstream_awb_memory(STREAMFILE* sf, STREAMFILE* sf_acb) { extension = "m4a"; } #endif - else { + else { /* 12=XMA? */ vgm_logi("AWB: unknown codec (report)\n"); goto fail; } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/bfwav.c b/Frameworks/vgmstream/vgmstream/src/meta/bfwav.c index 734fdc0c3..679aa7c69 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/bfwav.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/bfwav.c @@ -2,34 +2,31 @@ #include "../coding/coding.h" /* FWAV - Nintendo streams */ -VGMSTREAM * init_vgmstream_bfwav(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; +VGMSTREAM* init_vgmstream_bfwav(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; off_t start_offset; off_t info_offset, data_offset; - int channel_count, loop_flag, codec; + int channels, loop_flag, codec, sample_rate; int big_endian; size_t interleave = 0; int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL; int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL; - int nsmbu_flag = 0; /* checks */ + if (!is_id32be(0x00, sf, "FWAV")) + goto fail; + /* .bfwavnsmbu: fake extension to detect New Super Mario Bros U files with weird sample rate */ - if (!check_extensions(streamFile, "bfwav,fwav,bfwavnsmbu")) + if (!check_extensions(sf, "bfwav,fwav,bfwavnsmbu")) goto fail; - nsmbu_flag = check_extensions(streamFile, "bfwavnsmbu"); - /* FWAV header */ - if (read_32bitBE(0x00, streamFile) != 0x46574156) /* "FWAV" */ - goto fail; - /* 0x06(2): header size (0x40), 0x08: version (0x00010200), 0x0c: file size 0x10(2): sections (2) */ - - if ((uint16_t)read_16bitBE(0x04, streamFile) == 0xFEFF) { /* BE BOM check */ + /* BOM check */ + if (read_u16be(0x04, sf) == 0xFEFF) { read_32bit = read_32bitBE; read_16bit = read_16bitBE; big_endian = 1; - } else if ((uint16_t)read_16bitBE(0x04, streamFile) == 0xFFFE) { /* LE BOM check */ + } else if (read_u16be(0x04, sf) == 0xFFFE) { read_32bit = read_32bitLE; read_16bit = read_16bitLE; big_endian = 0; @@ -37,60 +34,74 @@ VGMSTREAM * init_vgmstream_bfwav(STREAMFILE *streamFile) { goto fail; } - info_offset = read_32bit(0x18, streamFile); /* 0x14(2): info mark (0x7000), 0x1c: info size */ - data_offset = read_32bit(0x24, streamFile); /* 0x20(2): data mark (0x7001), 0x28: data size */ + /* FWAV header */ + /* 0x06(2): header size (0x40) */ + /* 0x08: version (0x00010200) */ + /* 0x0c: file size */ + /* 0x10(2): sections (2) */ + + /* 0x14(2): info mark (0x7000) */ + info_offset = read_32bit(0x18, sf); + /* 0x1c: info size */ + + /* 0x20(2): data mark (0x7001) */ + data_offset = read_32bit(0x24, sf); + /* 0x28: data size */ /* INFO section */ - if (read_32bitBE(info_offset, streamFile) != 0x494E464F) /* "INFO" */ + if (!is_id32be(info_offset, sf, "INFO")) goto fail; - codec = read_8bit(info_offset + 0x08, streamFile); - loop_flag = read_8bit(info_offset + 0x09, streamFile); - channel_count = read_32bit(info_offset + 0x1C, streamFile); + codec = read_u8(info_offset + 0x08, sf); + loop_flag = read_u8(info_offset + 0x09, sf); + sample_rate = read_32bit(info_offset + 0x0C, sf); + channels = read_32bit(info_offset + 0x1C, sf); + + //TODO remove + if (check_extensions(sf, "bfwavnsmbu")) + sample_rate = 16000; /* parse channel table */ { off_t channel1_info, data_start; int i; - channel1_info = info_offset + 0x1c + read_32bit(info_offset+0x20+0x08*0+0x04, streamFile); - data_start = read_32bit(channel1_info+0x04, streamFile); /* within "DATA" after 0x08 */ + channel1_info = info_offset + 0x1c + read_32bit(info_offset+0x20+0x08*0+0x04, sf); + data_start = read_32bit(channel1_info+0x04, sf); /* within "DATA" after 0x08 */ /* channels use absolute offsets but should be ok as interleave */ interleave = 0; - if (channel_count > 1) { - off_t channel2_info = info_offset + 0x1c + read_32bit(info_offset+0x20+0x08*1+0x04, streamFile); - interleave = read_32bit(channel2_info+0x04, streamFile) - data_start; + if (channels > 1) { + off_t channel2_info = info_offset + 0x1c + read_32bit(info_offset+0x20+0x08*1+0x04, sf); + interleave = read_32bit(channel2_info+0x04, sf) - data_start; } start_offset = data_offset + 0x08 + data_start; /* validate all channels just in case of multichannel with non-constant interleave */ - for (i = 0; i < channel_count; i++) { + for (i = 0; i < channels; i++) { /* channel table, 0x00: flag (0x7100), 0x04: channel info offset */ - off_t channel_info = info_offset + 0x1c + read_32bit(info_offset+0x20+0x08*i+0x04, streamFile); + off_t channel_info = info_offset + 0x1c + read_32bit(info_offset+0x20+0x08*i+0x04, sf); /* channel info, 0x00(2): flag (0x1f00), 0x04: offset, 0x08(2): ADPCM flag (0x0300), 0x0c: ADPCM offset */ - if ((uint16_t)read_16bit(channel_info+0x00, streamFile) != 0x1F00) + if ((uint16_t)read_16bit(channel_info+0x00, sf) != 0x1F00) goto fail; - if (read_32bit(channel_info+0x04, streamFile) != data_start + interleave*i) + if (read_32bit(channel_info+0x04, sf) != data_start + interleave*i) goto fail; } } /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count, loop_flag); + vgmstream = allocate_vgmstream(channels, loop_flag); if (!vgmstream) goto fail; - vgmstream->sample_rate = read_32bit(info_offset + 0x0C, streamFile); - if (nsmbu_flag) - vgmstream->sample_rate = 16000; + vgmstream->sample_rate = sample_rate; - vgmstream->num_samples = read_32bit(info_offset + 0x14, streamFile); - vgmstream->loop_start_sample = read_32bit(info_offset + 0x10, streamFile); + vgmstream->num_samples = read_32bit(info_offset + 0x14, sf); + vgmstream->loop_start_sample = read_32bit(info_offset + 0x10, sf); vgmstream->loop_end_sample = vgmstream->num_samples; vgmstream->meta_type = meta_FWAV; - vgmstream->layout_type = (channel_count == 1) ? layout_none : layout_interleave; + vgmstream->layout_type = (channels == 1) ? layout_none : layout_interleave; vgmstream->interleave_block_size = interleave; switch (codec) { @@ -110,9 +121,9 @@ VGMSTREAM * init_vgmstream_bfwav(STREAMFILE *streamFile) { for (i = 0; i < vgmstream->channels; i++) { for (c = 0; c < 16; c++) { - coef_header = info_offset + 0x1C + read_32bit(info_offset + 0x24 + (i*0x08), streamFile); - coef_offset = read_32bit(coef_header + 0x0c, streamFile) + coef_header; - vgmstream->ch[i].adpcm_coef[c] = read_16bit(coef_offset + c*2, streamFile); + coef_header = info_offset + 0x1C + read_32bit(info_offset + 0x24 + (i*0x08), sf); + coef_offset = read_32bit(coef_header + 0x0c, sf) + coef_header; + vgmstream->ch[i].adpcm_coef[c] = read_16bit(coef_offset + c*2, sf); } } } @@ -123,7 +134,7 @@ VGMSTREAM * init_vgmstream_bfwav(STREAMFILE *streamFile) { } - if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + if (!vgmstream_open_stream(vgmstream,sf,start_offset)) goto fail; return vgmstream; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/csb.c b/Frameworks/vgmstream/vgmstream/src/meta/csb.c index a56bed015..68be6d72e 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/csb.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/csb.c @@ -13,7 +13,7 @@ VGMSTREAM* init_vgmstream_csb(STREAMFILE* sf) { utf_context *utf_sdl = NULL; int total_subsongs, target_subsong = sf->stream_index; uint8_t fmt = 0; - const char* stream_name; + const char* stream_name = NULL; /* checks */ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/encrypted.c b/Frameworks/vgmstream/vgmstream/src/meta/encrypted.c index e27a76584..1ecf83728 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/encrypted.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/encrypted.c @@ -38,9 +38,8 @@ VGMSTREAM* init_vgmstream_encrypted(STREAMFILE* sf) { temp_sf = setup_ogg_vorbis_streamfile(sf, cfg); if (!temp_sf) goto fail; -#ifdef VGM_USE_VORBIS + vgmstream = init_vgmstream_ogg_vorbis(temp_sf); -#endif close_streamfile(temp_sf); return vgmstream; } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ffdl.c b/Frameworks/vgmstream/vgmstream/src/meta/ffdl.c index b9440b618..866dbe1ac 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ffdl.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ffdl.c @@ -1,97 +1,96 @@ -#include "meta.h" -#include "../coding/coding.h" - - -/* FFDL - Matrix Software wrapper [Final Fantasy Dimensions (Android/iOS)] */ -VGMSTREAM * init_vgmstream_ffdl(STREAMFILE *sf) { - VGMSTREAM * vgmstream = NULL; - STREAMFILE *temp_sf = NULL; - int loop_flag = 0, is_ffdl = 0; - int32_t num_samples = 0, loop_start_sample = 0, loop_end_sample = 0; - off_t start_offset; - size_t file_size; - - - /* checks */ - /* .ogg/logg: probable extension for Android - * .mp4/lmp4: probable extension for iOS - * .bin: iOS FFDL extension - * (extensionless): for FFDL files without names in Android .obb bigfile */ - if (!check_extensions(sf, "ogg,logg,mp4,lmp4,bin,")) - goto fail; - - /* "FFDL" is a wrapper used in all of the game's files, that may contain standard - * Ogg/MP4 or "mtxs" w/ loops + Ogg/MP4, and may concatenate multiple of them - * (without size in sight), so they should be split externally first. */ - - start_offset = 0x00; - - /* may start with wrapper (not split) */ - if (read_u32be(0x00,sf) == 0x4646444C) { /* "FFDL" */ - is_ffdl = 1; - start_offset += 0x04; - } - - /* may start with sample info (split) or after "FFDL" */ - if (read_u32be(start_offset+0x00,sf) == 0x6D747873) { /* "mtxs" */ - is_ffdl = 1; - - num_samples = read_s32le(start_offset + 0x04,sf); - loop_start_sample = read_s32le(start_offset + 0x08,sf); - loop_end_sample = read_s32le(start_offset + 0x0c,sf); - loop_flag = !(loop_start_sample==0 && loop_end_sample==num_samples); - - start_offset += 0x10; - } - - /* don't parse regular files */ - if (!is_ffdl) - goto fail; - - file_size = get_streamfile_size(sf) - start_offset; - - if (read_u32be(start_offset + 0x00,sf) == 0x4F676753) { /* "OggS" */ -#ifdef VGM_USE_VORBIS - temp_sf = setup_subfile_streamfile(sf, start_offset, file_size, "ogg"); - if (!temp_sf) goto fail; - - vgmstream = init_vgmstream_ogg_vorbis(temp_sf); - if (!vgmstream) goto fail; -#else - goto fail; -#endif - } - else if (read_u32be(start_offset + 0x04,sf) == 0x66747970) { /* "ftyp" after atom size */ -#ifdef VGM_USE_FFMPEG - temp_sf = setup_subfile_streamfile(sf, start_offset, file_size, "mp4"); - if (!temp_sf) goto fail; - - vgmstream = init_vgmstream_mp4_aac_ffmpeg(temp_sf); - if (!vgmstream) goto fail; -#else - goto fail; -#endif - } - else { - goto fail; - } - - /* install loops */ - if (loop_flag) { - /* num_samples is erratic (can be bigger = padded, or smaller = cut; doesn't matter for looping though) */ - //;VGM_ASSERT(vgmstream->num_samples != num_samples, - // "FFDL: mtxs samples = %i vs num_samples = %i\n", num_samples, vgmstream->num_samples); - //vgmstream->num_samples = num_samples; - - /* loop samples are within num_samples, and don't have encoder delay (loop_start=0 starts from encoder_delay) */ - vgmstream_force_loop(vgmstream, 1, loop_start_sample, loop_end_sample); - } - - close_streamfile(temp_sf); - return vgmstream; - -fail: - close_streamfile(temp_sf); - close_vgmstream(vgmstream); - return NULL; -} +#include "meta.h" +#include "../coding/coding.h" + + +/* FFDL - Matrix Software wrapper [Final Fantasy Dimensions (Android/iOS)] */ +VGMSTREAM* init_vgmstream_ffdl(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + STREAMFILE* temp_sf = NULL; + int loop_flag = 0, is_ffdl = 0; + int32_t num_samples = 0, loop_start_sample = 0, loop_end_sample = 0; + off_t start_offset; + size_t file_size; + + + /* checks */ + if (!is_id32be(0x00,sf, "FFDL") && + !is_id32be(0x00,sf, "mtxs")) + goto fail; + + /* .ogg/logg: probable extension for Android + * .mp4/lmp4: probable extension for iOS + * .bin: iOS FFDL extension + * (extensionless): for FFDL files without names in Android .obb bigfile */ + if (!check_extensions(sf, "ogg,logg,mp4,lmp4,bin,")) + goto fail; + + /* "FFDL" is a wrapper used in all of the game's files, that may contain standard + * Ogg/MP4 or "mtxs" w/ loops + Ogg/MP4, and may concatenate multiple of them + * (without size in sight), so they should be split externally first. */ + + /* may start with wrapper (not split) */ + start_offset = 0x00; + if (is_id32be(0x00,sf, "FFDL")) { + is_ffdl = 1; + start_offset += 0x04; + } + + /* may start with sample info (split) or after "FFDL" */ + if (is_id32be(start_offset+0x00,sf, "mtxs")) { + is_ffdl = 1; + + num_samples = read_s32le(start_offset + 0x04,sf); + loop_start_sample = read_s32le(start_offset + 0x08,sf); + loop_end_sample = read_s32le(start_offset + 0x0c,sf); + loop_flag = !(loop_start_sample==0 && loop_end_sample==num_samples); + + start_offset += 0x10; + } + + /* don't parse regular files */ + if (!is_ffdl) + goto fail; + + file_size = get_streamfile_size(sf) - start_offset; + + if (read_u32be(start_offset + 0x00,sf) == 0x4F676753) { /* "OggS" */ + temp_sf = setup_subfile_streamfile(sf, start_offset, file_size, "ogg"); + if (!temp_sf) goto fail; + + vgmstream = init_vgmstream_ogg_vorbis(temp_sf); + if (!vgmstream) goto fail; + } + else if (read_u32be(start_offset + 0x04,sf) == 0x66747970) { /* "ftyp" after atom size */ +#ifdef VGM_USE_FFMPEG + temp_sf = setup_subfile_streamfile(sf, start_offset, file_size, "mp4"); + if (!temp_sf) goto fail; + + vgmstream = init_vgmstream_mp4_aac_ffmpeg(temp_sf); + if (!vgmstream) goto fail; +#else + goto fail; +#endif + } + else { + goto fail; + } + + /* install loops */ + if (loop_flag) { + /* num_samples is erratic (can be bigger = padded, or smaller = cut; doesn't matter for looping though) */ + //;VGM_ASSERT(vgmstream->num_samples != num_samples, + // "FFDL: mtxs samples = %i vs num_samples = %i\n", num_samples, vgmstream->num_samples); + //vgmstream->num_samples = num_samples; + + /* loop samples are within num_samples, and don't have encoder delay (loop_start=0 starts from encoder_delay) */ + vgmstream_force_loop(vgmstream, 1, loop_start_sample, loop_end_sample); + } + + close_streamfile(temp_sf); + return vgmstream; + +fail: + close_streamfile(temp_sf); + close_vgmstream(vgmstream); + return NULL; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/fsb5.c b/Frameworks/vgmstream/vgmstream/src/meta/fsb5.c index 24c9b801a..e91950135 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/fsb5.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/fsb5.c @@ -18,10 +18,10 @@ typedef struct { int32_t loop_end; int loop_flag; - size_t sample_header_size; - size_t name_table_size; - size_t sample_data_size; - size_t base_header_size; + uint32_t sample_header_size; + uint32_t name_table_size; + uint32_t sample_data_size; + uint32_t base_header_size; uint32_t extradata_offset; uint32_t extradata_size; @@ -46,15 +46,15 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) { /* checks */ + if (!is_id32be(0x00,sf, "FSB5")) + goto fail; + /* .fsb: standard * .snd: Alchemy engine (also Unity) */ if (!check_extensions(sf,"fsb,snd")) goto fail; - if (!is_id32be(0x00,sf, "FSB5")) - goto fail; - - /* v0 is rare (seen in Tales from Space Vita) */ + /* v0 is rare, seen in Tales from Space (Vita) */ fsb5.version = read_u32le(0x04,sf); if (fsb5.version != 0x00 && fsb5.version != 0x01) goto fail; @@ -80,7 +80,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) { } if ((fsb5.sample_header_size + fsb5.name_table_size + fsb5.sample_data_size + fsb5.base_header_size) != get_streamfile_size(sf)) { - vgm_logi("FSB5: wrong size, expected %x + %x + %x + %x vs %x (re-rip)\n", fsb5.sample_header_size, fsb5.name_table_size, fsb5.sample_data_size, fsb5.base_header_size, get_streamfile_size(sf)); + vgm_logi("FSB5: wrong size, expected %x + %x + %x + %x vs %x (re-rip)\n", fsb5.sample_header_size, fsb5.name_table_size, fsb5.sample_data_size, fsb5.base_header_size, (uint32_t)get_streamfile_size(sf)); goto fail; } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/hca.c b/Frameworks/vgmstream/vgmstream/src/meta/hca.c index d7694ca9d..1a9fb4864 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/hca.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/hca.c @@ -191,10 +191,21 @@ done: } #ifdef HCA_BRUTEFORCE +typedef enum { + HBF_TYPE_64LE_1, + HBF_TYPE_64BE_1, + HBF_TYPE_32LE_1, + HBF_TYPE_32BE_1, + HBF_TYPE_64LE_4, + HBF_TYPE_64BE_4, + HBF_TYPE_32LE_4, + HBF_TYPE_32BE_4, +} HBF_type_t; + /* Bruteforce binary keys in executables and similar files, mainly for some mobile games. * Kinda slow but acceptable for ~20MB exes, not very optimized. Unity usually has keys * in plaintext (inside levelX or other base files) instead though. */ -static void bruteforce_hca_key_bin(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey) { +static void bruteforce_hca_key_bin_type(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey, HBF_type_t type) { STREAMFILE* sf_keys = NULL; uint8_t* buf = NULL; int best_score = 0xFFFFFF, cur_score; @@ -203,7 +214,7 @@ static void bruteforce_hca_key_bin(STREAMFILE* sf, hca_codec_data* hca_data, uns uint64_t old_key = 0; - VGM_LOG("HCA: test keys.bin\n"); + VGM_LOG("HCA: test keys.bin (type %i)\n", type); *p_keycode = 0; @@ -226,17 +237,18 @@ static void bruteforce_hca_key_bin(STREAMFILE* sf, hca_codec_data* hca_data, uns uint64_t key; VGM_ASSERT(pos % 0x1000000 == 0, "HCA: pos %x...\n", pos); - /* keys are usually u32le lower, u32le upper (u64le) but other orders may exist */ - key = ((uint64_t)get_u32le(buf + pos + 0x00) << 0 ) | ((uint64_t)get_u32le(buf + pos + 0x04) << 32); - //key = ((uint64_t)get_u32le(buf + pos + 0x00) << 32) | ((uint64_t)get_u32le(buf + pos + 0x04) << 0); - //key = ((uint64_t)get_u32be(buf + pos + 0x00) << 0 ) | ((uint64_t)get_u32be(buf + pos + 0x04) << 32); - //key = ((uint64_t)get_u32be(buf + pos + 0x00) << 32) | ((uint64_t)get_u32be(buf + pos + 0x04) << 0); - //key = ((uint64_t)get_u32le(buf + pos + 0x00) << 0 ) | 0; /* upper bytes not set, ex. P5 */ - //key = ((uint64_t)get_u32be(buf + pos + 0x00) << 0 ) | 0; /* upper bytes not set, ex. P5 */ - - /* observed files have aligned keys, change if needed */ - pos += 0x04; - //pos++; + /* keys are usually u64le but other orders may exist */ + switch(type) { + case HBF_TYPE_64LE_1: key = get_u64le(buf + pos); pos += 0x01; break; + case HBF_TYPE_64BE_1: key = get_u64be(buf + pos); pos += 0x01; break; + case HBF_TYPE_32LE_1: key = get_u32le(buf + pos); pos += 0x01; break; + case HBF_TYPE_32BE_1: key = get_u32be(buf + pos); pos += 0x01; break; + case HBF_TYPE_64LE_4: key = get_u64le(buf + pos); pos += 0x04; break; + case HBF_TYPE_64BE_4: key = get_u64be(buf + pos); pos += 0x04; break; + case HBF_TYPE_32LE_4: key = get_u32le(buf + pos); pos += 0x04; break; + case HBF_TYPE_32BE_4: key = get_u32be(buf + pos); pos += 0x04; break; + default: key = 0; pos = keys_size; break; + } if (key == 0 || key == old_key) continue; @@ -266,6 +278,18 @@ done: free(buf); } +static void bruteforce_hca_key_bin(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey) { + bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_64LE_4); + bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_64BE_4); + bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_32LE_4); + bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_32BE_4); + bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_64LE_1); + bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_64BE_1); + bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_32LE_1); + bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_32BE_1); +} + + #include //#include @@ -303,14 +327,13 @@ static void bruteforce_hca_key_txt(STREAMFILE* sf, hca_codec_data* hca_data, uns uint64_t key = 0; bytes_read = read_line(line, sizeof(line), pos, sf_keys, &line_ok); - if (!line_ok) continue; //??? - pos += bytes_read; + if (!line_ok) continue; /* line too long */ count = sscanf(line, "%" SCNd64, &key); if (count != 1) continue; - VGM_ASSERT(pos % 100000 == 0, "HCA: count %i...\n", i); + VGM_ASSERT(pos % 10000 == 0, "HCA: count %i...\n", i); if (key == 0) continue; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h b/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h index 5c6d2695c..616cad7f7 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h +++ b/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h @@ -435,6 +435,8 @@ static const hcakey_info hcakey_list[] = { {0x2f778c736a8a4597}, //music_0110015 {0xa90c8ebf8463d05}, //music_0110016 {0x750beaf22ddc700b}, //music_0110018 + {0x16ccc93f976a8329}, //music_0110019 + {0x9f7a0810034669fe}, //music_0110020 {0xfb647d074e53fab6}, //music_0120001 {0xc24049b9f7ed3105}, //music_0120002 {0xdc128f2fd48bf4b}, //music_0120003 @@ -450,7 +452,9 @@ static const hcakey_info hcakey_list[] = { {0x6ba36cadf1e045cf}, //music_0120013 {0xb96786621e27daf3}, //music_0120014 {0xa2c543b227b8e5e2}, //music_0120015 + {0x845437ec4e367a13}, //music_0120016 {0x3674aba8da7bc84b}, //music_0120018 + {0xfd61f2c3b89f3888}, //music_0120019 {0x4fffee4065d22bec}, //music_0210001 {0x7678588b0adf59df}, //music_0210002 {0xa0316b536c8b7540}, //music_0210003 @@ -461,6 +465,7 @@ static const hcakey_info hcakey_list[] = { {0x73621a0d321e60c2}, //music_0210008 {0xff04547fe629c8bf}, //music_0210009 {0x5ef795cdbcdcba91}, //music_0210010 + {0x868acc0102c59a38}, //music_0210011 {0x15bb78c31db0a0b6}, //music_0220001 {0x59b1257242c40109}, //music_0220002 {0xdb402bd08d522f34}, //music_0220003 @@ -474,6 +479,7 @@ static const hcakey_info hcakey_list[] = { {0xf0c624dc0385adae}, //music_0220011 {0xce0796d2a956dc5a}, //music_0220012 {0xf9d6fb07c0b4e967}, //music_0220013 + {0x4aa31e0c4f787a8}, //music_0220014 {0x94466db0d3c10f4b}, //music_0220015 {0xe6d1fd6effa46736}, //music_0220017 {0x6a15a9610d10d210}, //music_0310001 @@ -502,6 +508,7 @@ static const hcakey_info hcakey_list[] = { {0x244a92885ab77b7c}, //music_0320012 {0xfc3fa77fc33460d4}, //music_0320013 {0x26ee13598091b548}, //music_0320014 + {0x2df608ef06aca41c}, //music_0320016 {0x776c4aded0bca5d1}, //music_0410001 {0xb7bff4fbf66be43f}, //music_0410002 {0x904f50c5ce8ec6e4}, //music_0410003 @@ -527,6 +534,7 @@ static const hcakey_info hcakey_list[] = { {0x52723f026d5238e8}, //music_0420012 {0xd13a315c0005f0}, //music_0420013 {0x35f2d3cec84aba1}, //music_0420014 + {0xdad11fe0e397ede}, //music_0420015 {0xdf31e26a7b036a2}, //music_0510001 {0xb2770dced3cfd9a7}, //music_0510002 {0x6c6c1fd51e28a1e7}, //music_0510003 @@ -540,6 +548,7 @@ static const hcakey_info hcakey_list[] = { {0xc5c9bf138c9e28ce}, //music_0510011 {0x1980271cfe0da9bd}, //music_0510012 {0x75c5bd4e3a01a8a4}, //music_0510013 + {0xec5f5fbe92bbb771}, //music_0510014 {0x15f82c1617013c36}, //music_0520001 {0xc7da8e6f0e2fe399}, //music_0520002 {0xe350bffcdc9cb686}, //music_0520003 @@ -552,6 +561,7 @@ static const hcakey_info hcakey_list[] = { {0xde4959221bc2675}, //music_0520010 {0xeeaf8d2458ccdb36}, //music_0520011 {0xb140168a47d55b92}, //music_0520012 + {0x1bf43def1e4b103a}, //music_0520014 {0xd2ce91dbfc209b10}, //music_0610001 {0xa662be1601e49476}, //music_0610002 {0xe5e83d31e64273f8}, //music_0610003 @@ -576,6 +586,7 @@ static const hcakey_info hcakey_list[] = { {0x33848be13a2884a3}, //music_0620011 {0xfab3596f11cc4d7a}, //music_0620012 {0xe35d52b6d2c094fb}, //music_0620013 + {0xcdb9bc2ad7024ca2}, //music_0620014 {0x2a47feac8dc3ca9c}, //music_3010001 {0x9ebbaf63ffe9d9ef}, //music_3010002 {0xe553dba6592293d8}, //music_3010003 @@ -586,12 +597,16 @@ static const hcakey_info hcakey_list[] = { {0x1ab266a4cbb5133a}, //music_3010008 {0x7d4719615fbb2f4d}, //music_3010009 {0x28aa75a01f26a853}, //music_3010010 + {0x7555feeaa2a8fac4}, //music_3010011 {0xa42de67a89fb3175}, //music_3010012 + {0xbdd0c58062c675d4}, //music_3010014 {0xfd3ea450350d666f}, //music_3020001 {0x5e91a3790c32e2b3}, //music_3020002 {0x358adfd1bbd3a95e}, //music_3020003 {0x1948edf7ff41e79b}, //music_3020004 {0x100293729f35b4de}, //music_3020005 + {0x140ac59d2b870a13}, //music_3020006 + {0x402b13df5481d4e6}, //music_3020007 {0xdfad847a86a126bb}, //music_5030001 {0x711ef85045b8c26e}, //music_5030002 {0xff7640b46d72b337}, //music_5030003 @@ -623,6 +638,8 @@ static const hcakey_info hcakey_list[] = { {0x24c0b49097e9ebff}, //music_5030029 {0x2ecdf66c680f3a45}, //music_5030030 {0x54aaada4a1b8deef}, //music_5030031 + {0x46bed365593c560c}, //music_5030032 + {0xa954b315630e3ed0}, //music_5030033 {0x8328668369631cc1}, //music_5030034 {0xa5c1adeb7919845f}, //music_5030035 {0x8e35d68632fc0d77}, //music_5030036 @@ -631,6 +648,9 @@ static const hcakey_info hcakey_list[] = { {0x6abcc90be62f2cec}, //music_5030039 {0x7f617e396e9a1e5c}, //music_5030040 {0xd0471c163265ca1b}, //music_5030041 + {0xd689966609595d7d}, //music_5030042 + {0x32cb728ddab4d956}, //music_5030050 + {0x52c5dfb61fe4c87a}, //music_5030054 {0x444dda6d55d76095}, //music_5040001 {0xcbf4f1324081e0a6}, //music_5040002 {0xf1db3c1d9542063a}, //music_5040003 @@ -688,6 +708,10 @@ static const hcakey_info hcakey_list[] = { {0xfa842bc07360137d}, //music_5050035 {0xf8d72c405d3f0456}, //music_5050036 {0xd4d5fa6c87342e6b}, //music_5050037 + {0xd8cbc946fa660944}, //music_5050038 + {0xfac398719cd9e4a}, //music_5050039 + {0x9c4ba796548a019}, //music_5050040 + {0x7e7c462ba7d473cf}, //music_5050041 {0xe278eccf08eb2565}, //music_5050044 {0x1cf133b26d8160d1}, //music_5050045 {0xda08e9d3961c93f2}, //music_5050046 @@ -702,6 +726,7 @@ static const hcakey_info hcakey_list[] = { {0xbce9e85d31089fb2}, //music_5050056 {0x817b919679c96d7}, //music_5050057 {0x3e0e51043bd7d5e5}, //music_5050058 + {0x86d17e28b2f2b91c}, //music_5050059 {0x115f906b6b7fb845}, //music_5050060 {0xa8d5e9b1c6cf1505}, //music_5050061 {0x69ffd3fefdf7ee71}, //music_5050062 @@ -710,10 +735,21 @@ static const hcakey_info hcakey_list[] = { {0x27992dd621b8a07e}, //music_5050065 {0x8e2a8439f5628513}, //music_5050066 {0x8b5be21e70a84eed}, //music_5050067 + {0x227297416c6ccc7c}, //music_5050068 {0xb544dc8524419109}, //music_5050069 {0x6c2d9160672cbf95}, //music_5050070 {0x7ff6630286d2d93b}, //music_5050071 + {0xc6deecd2d1391713}, //music_5050072 {0x78bec41dd27d8788}, //music_5050074 + {0xf86991a3b9aec2b}, //music_5050075 + {0x8f750fabaa794130}, //music_5050076 + {0x3c68e8102dbec720}, //music_5050077 + {0xf653b47bc8d4d1cd}, //music_5050079 + {0xb50f482149140fda}, //music_5050080 + {0xd61cc4e14e7073f4}, //music_5050081 + {0x85a236b5270bac29}, //music_5050083 + {0x598e133e0673b1e6}, //music_5050086 + {0x3f8abfcd47711be2}, //music_5050088 {0x52c250eade92393b}, //music_9010001 {0xfea0d6adff136868}, //music_9050001 diff --git a/Frameworks/vgmstream/vgmstream/src/meta/his.c b/Frameworks/vgmstream/vgmstream/src/meta/his.c index e9b9fdcd4..3034db0e1 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/his.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/his.c @@ -5,47 +5,50 @@ /* HIS - Her Interactive games [Nancy Drew series (PC)] */ VGMSTREAM * init_vgmstream_his(STREAMFILE *sf) { VGMSTREAM * vgmstream = NULL; - int channel_count, loop_flag = 0, bps, sample_rate, num_samples, version; + int channels, loop_flag = 0, bps, sample_rate, num_samples, version; off_t start_offset; /* checks */ + if (!is_id32be(0x00,sf, "Her ") && + !is_id32be(0x00,sf, "HIS\0")) + goto fail; if (!check_extensions(sf, "his")) goto fail; - if (read_32bitBE(0x00,sf) == 0x48657220) { /* "Her Interactive Sound\x1a" */ + if (is_id32be(0x00,sf, "Her ")) { /* "Her Interactive Sound\x1a" */ /* Nancy Drew: Secrets Can Kill (PC) */ version = 0; - channel_count = read_16bitLE(0x16,sf); - sample_rate = read_32bitLE(0x18,sf); + channels = read_u16le(0x16,sf); + sample_rate = read_u32le(0x18,sf); /* 0x1c: bitrate */ /* 0x20: block size */ - bps = read_16bitLE(0x22,sf); + bps = read_u16le(0x22,sf); - if (read_32bitBE(0x24,sf) != 0x64617461) /* "data" */ + if (!is_id32be(0x24,sf, "data")) goto fail; - num_samples = pcm_bytes_to_samples(read_32bitLE(0x28,sf), channel_count, bps); + num_samples = pcm_bytes_to_samples(read_u32le(0x28,sf), channels, bps); start_offset = 0x2c; } - else if (read_32bitBE(0x00,sf) == 0x48495300) { /* HIS\0 */ + else if (is_id32be(0x00,sf, "HIS\0")) { /* most(?) others */ - version = read_32bitLE(0x04,sf); + version = read_u32le(0x04,sf); /* 0x08: codec */ - channel_count = read_16bitLE(0x0a,sf); - sample_rate = read_32bitLE(0x0c,sf); + channels = read_u16le(0x0a,sf); + sample_rate = read_u32le(0x0c,sf); /* 0x10: bitrate */ /* 0x14: block size */ - bps = read_16bitLE(0x16,sf); + bps = read_u16le(0x16,sf); - num_samples = pcm_bytes_to_samples(read_32bitLE(0x18,sf), channel_count, bps); /* true even for Ogg */ + num_samples = pcm_bytes_to_samples(read_u32le(0x18,sf), channels, bps); /* true even for Ogg */ /* later games use "OggS" */ if (version == 1) start_offset = 0x1c; /* Nancy Drew: The Final Scene (PC) */ - else if (version == 2 && read_32bitBE(0x1e,sf) == 0x4F676753) + else if (version == 2 && is_id32be(0x1e,sf, "OggS")) start_offset = 0x1e; /* Nancy Drew: The Haunted Carousel (PC) */ - else if (version == 2 && read_32bitBE(0x20,sf) == 0x4F676753) + else if (version == 2 && is_id32be(0x20,sf, "OggS")) start_offset = 0x20; /* Nancy Drew: The Silent Spy (PC) */ else goto fail; @@ -56,18 +59,14 @@ VGMSTREAM * init_vgmstream_his(STREAMFILE *sf) { if (version == 2) { -#ifdef VGM_USE_VORBIS ogg_vorbis_meta_info_t ovmi = {0}; ovmi.meta_type = meta_HIS; return init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi); -#else - goto fail; -#endif } /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); + vgmstream = allocate_vgmstream(channels, loop_flag); if (!vgmstream) goto fail; vgmstream->meta_type = meta_HIS; @@ -89,7 +88,7 @@ VGMSTREAM * init_vgmstream_his(STREAMFILE *sf) { goto fail; } - if (!vgmstream_open_stream(vgmstream,sf,start_offset)) + if (!vgmstream_open_stream(vgmstream, sf, start_offset)) goto fail; return vgmstream; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ikm.c b/Frameworks/vgmstream/vgmstream/src/meta/ikm.c index 57962d15c..f73db803e 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ikm.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ikm.c @@ -10,14 +10,14 @@ VGMSTREAM* init_vgmstream_ikm_ps2(STREAMFILE* sf) { /* checks */ - if ( !check_extensions(sf,"ikm") ) + if (!is_id32be(0x00,sf, "IKM\0")) goto fail; - if (read_u32be(0x00,sf) != 0x494B4D00) /* "IKM\0" */ + if (!check_extensions(sf,"ikm")) goto fail; - if (read_u32be(0x40,sf) != 0x41535400) /* "AST\0" */ - goto fail; /* 0x20: type 03? */ + if (!is_id32be(0x40,sf, "AST\0")) + goto fail; loop_flag = (read_s32le(0x14, sf) > 0); channel_count = read_s32le(0x50, sf); @@ -53,23 +53,24 @@ VGMSTREAM* init_vgmstream_ikm_pc(STREAMFILE* sf) { /* checks */ - if ( !check_extensions(sf,"ikm") ) + if (!is_id32be(0x00,sf, "IKM\0")) goto fail; - if (read_u32be(0x00,sf) != 0x494B4D00) /* "IKM\0" */ + if (!check_extensions(sf,"ikm")) goto fail; /* 0x20: type 01? */ /* find "OggS" start */ - if (read_u32be(0x30,sf) == 0x4F676753) { + if (is_id32be(0x30,sf, "OggS")) { start_offset = 0x30; /* Chaos Legion (PC) */ - } else if (read_u32be(0x800,sf) == 0x4F676753) { + } + else if (is_id32be(0x800,sf, "OggS")) { start_offset = 0x800; /* Legend of Galactic Heroes (PC) */ - } else { + } + else { goto fail; } -#ifdef VGM_USE_VORBIS { ogg_vorbis_meta_info_t ovmi = {0}; @@ -82,9 +83,6 @@ VGMSTREAM* init_vgmstream_ikm_pc(STREAMFILE* sf) { vgmstream = init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi); } -#else - goto fail; -#endif return vgmstream; @@ -102,13 +100,14 @@ VGMSTREAM* init_vgmstream_ikm_psp(STREAMFILE* sf) { /* checks */ + if (!is_id32be(0x00,sf, "IKM\0")) + goto fail; if (!check_extensions(sf,"ikm")) goto fail; - if (read_u32be(0x00,sf) != 0x494B4D00) /* "IKM\0" */ - goto fail; - if (read_u32be(0x800,sf) != 0x52494646) /* "RIFF" */ - goto fail; + /* 0x20: type 00? */ + if (!is_id32be(0x800,sf, "RIFF")) + goto fail; /* loop values (pre-adjusted without encoder delay) at 0x14/18 are found in the RIFF too */ data_size = read_s32le(0x24, sf); diff --git a/Frameworks/vgmstream/vgmstream/src/meta/imuse.c b/Frameworks/vgmstream/vgmstream/src/meta/imuse.c index a8706ebec..112e0a466 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/imuse.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/imuse.c @@ -2,13 +2,6 @@ #include "../coding/coding.h" -static int is_id4(const char* test, off_t offset, STREAMFILE* sf) { - uint8_t buf[4]; - if (read_streamfile(buf, offset, sizeof(buf), sf) != sizeof(buf)) - return 0; - return memcmp(buf, test, sizeof(buf)) == 0; /* memcmp to allow "AB\0\0" */ -} - /* LucasArts iMUSE (Interactive Music Streaming Engine) formats */ VGMSTREAM* init_vgmstream_imuse(STREAMFILE* sf) { VGMSTREAM* vgmstream = NULL; @@ -19,19 +12,13 @@ VGMSTREAM* init_vgmstream_imuse(STREAMFILE* sf) { /* checks */ - /* .imx: The Curse of Monkey Island (PC) - * .imc: Grim Fandango (multi) - * .wav: Grim Fandango (multi) RIFF sfx */ - if (!check_extensions(sf, "imx,imc,wav,lwav")) - goto fail; - /* base decoder block table */ - if (is_id4("COMP", 0x00, sf)) { /* The Curse of Monkey Island (PC), The Dig (PC) */ + if (is_id32be(0x00, sf, "COMP")) { /* The Curse of Monkey Island (PC), The Dig (PC) */ int entries = read_u32be(0x04,sf); head_offset = 0x10 + entries * 0x10 + 0x02; /* base header + table + header size */ } - else if (is_id4("MCMP", 0x00, sf)) { /* Grim Fandango (multi), Star Wars: X-Wing Alliance (PC) */ + else if (is_id32be(0x00, sf, "MCMP")) { /* Grim Fandango (multi), Star Wars: X-Wing Alliance (PC) */ int entries = read_u16be(0x04,sf); head_offset = 0x06 + entries * 0x09; /* base header + table */ head_offset += 0x02 + read_u16be(head_offset, sf); /* + mini text header */ @@ -40,17 +27,23 @@ VGMSTREAM* init_vgmstream_imuse(STREAMFILE* sf) { goto fail; } + /* .imx: The Curse of Monkey Island (PC) + * .imc: Grim Fandango (multi) + * .wav: Grim Fandango (multi) RIFF sfx */ + if (!check_extensions(sf, "imx,imc,wav,lwav")) + goto fail; + /* "offsets" below seem to count decoded data. Data is divided into variable-sized blocks that usually * return 0x2000 bytes (starting from and including header). File starts with a block table to make * this manageable. Most offsets don't seem to match block or data boundaries so not really sure. */ /* main header after table */ - if (is_id4("iMUS", head_offset, sf)) { /* COMP/MCMP */ + if (is_id32be(head_offset, sf, "iMUS")) { /* COMP/MCMP */ int header_found = 0; /* 0x04: decompressed size (header size + pcm bytes) */ - if (!is_id4("MAP ", head_offset + 0x08, sf)) + if (!is_id32be(head_offset + 0x08, sf, "MAP ")) goto fail; map_size = read_u32be(head_offset + 0x0c, sf); map_offset = head_offset + 0x10; @@ -105,12 +98,12 @@ VGMSTREAM* init_vgmstream_imuse(STREAMFILE* sf) { if (!header_found) goto fail; - if (!is_id4("DATA", head_offset + 0x10 + map_size + 0x00, sf)) + if (!is_id32be(head_offset + 0x10 + map_size + 0x00, sf, "DATA")) goto fail; data_bytes = read_u32be(head_offset + 0x10 + map_size + 0x04, sf); num_samples = data_bytes / channels / sizeof(int16_t); } - else if (is_id4("RIFF", head_offset, sf)) { /* MCMP voices */ + else if (is_id32be(head_offset, sf, "RIFF")) { /* MCMP voices */ /* standard (LE), with fake codec 1 and sizes also in decoded bytes (see above), * has standard RIFF chunks (may include extra), start offset in MCSC */ @@ -124,7 +117,8 @@ VGMSTREAM* init_vgmstream_imuse(STREAMFILE* sf) { num_samples = data_bytes / channels / sizeof(int16_t); } else { - goto fail; /* The Dig (PC) has no header, detect? */ + vgm_logi("IMUSE: unsupported format\n"); + goto fail; /* The Dig (PC) has no header, detect? (needs a bunch of sub-codecs) */ } loop_flag = 0; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/meta.h b/Frameworks/vgmstream/vgmstream/src/meta/meta.h index 807a6d758..32d354d94 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/meta.h +++ b/Frameworks/vgmstream/vgmstream/src/meta/meta.h @@ -3,6 +3,8 @@ #include "../vgmstream.h" +typedef VGMSTREAM* (*init_vgmstream_t)(STREAMFILE* sf); + VGMSTREAM* init_vgmstream_silence(int channels, int sample_rate, int32_t num_samples); VGMSTREAM* init_vgmstream_silence_container(int total_subsongs); @@ -116,8 +118,7 @@ VGMSTREAM * init_vgmstream_vpk(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile); -#ifdef VGM_USE_VORBIS -VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile); +VGMSTREAM* init_vgmstream_ogg_vorbis(STREAMFILE* sf); typedef struct { int loop_flag; @@ -142,16 +143,15 @@ typedef struct { } ogg_vorbis_meta_info_t; -VGMSTREAM* init_vgmstream_ogg_vorbis_config(STREAMFILE *sf, off_t start, const ogg_vorbis_meta_info_t* ovmi); -#endif +VGMSTREAM* init_vgmstream_ogg_vorbis_config(STREAMFILE* sf, off_t start, const ogg_vorbis_meta_info_t* ovmi); -VGMSTREAM * init_vgmstream_hca(STREAMFILE *streamFile); -VGMSTREAM * init_vgmstream_hca_subkey(STREAMFILE *streamFile, uint16_t subkey); +VGMSTREAM* init_vgmstream_hca(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_hca_subkey(STREAMFILE* sf, uint16_t subkey); #ifdef VGM_USE_FFMPEG -VGMSTREAM * init_vgmstream_ffmpeg(STREAMFILE *streamFile); +VGMSTREAM* init_vgmstream_ffmpeg(STREAMFILE* sf); -VGMSTREAM * init_vgmstream_mp4_aac_ffmpeg(STREAMFILE * streamFile); +VGMSTREAM* init_vgmstream_mp4_aac_ffmpeg(STREAMFILE* sf); #endif #if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC) diff --git a/Frameworks/vgmstream/vgmstream/src/meta/mogg.c b/Frameworks/vgmstream/vgmstream/src/meta/mogg.c index 40be9d998..e08e98667 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/mogg.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/mogg.c @@ -1,39 +1,27 @@ -/* -2017-12-10: Preliminary MOGG Support. As long as the stream is unencrypted, this should be fine. - This will also work on unconventional 5 channel Vorbis streams but some sound cards might not like it. - TODO (Eventually): Add decryption for encrypted MOGG types (Rock Band, etc.) - - -bxaimc -*/ - #include "meta.h" #include "../coding/coding.h" -/* MOGG - Harmonix Music Systems (Guitar Hero)[Unencrypted Type] */ -VGMSTREAM* init_vgmstream_mogg(STREAMFILE *sf) { -#ifdef VGM_USE_VORBIS +/* MOGG - Harmonix Music Systems's Ogg (unencrypted type) [Guitar Hero II (X360)] */ +VGMSTREAM* init_vgmstream_mogg(STREAMFILE* sf) { off_t start_offset; + /* checks */ + if (read_u32le(0x00, sf) != 0x0A) /* type? */ + goto fail; + if (!check_extensions(sf, "mogg")) goto fail; { ogg_vorbis_meta_info_t ovmi = {0}; - VGMSTREAM * result = NULL; ovmi.meta_type = meta_MOGG; - start_offset = read_32bitLE(0x04, sf); - result = init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi); - - if (result != NULL) { - return result; - } + start_offset = read_u32le(0x04, sf); + return init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi); } fail: - /* clean up anything we may have opened */ -#endif return NULL; } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/mups.c b/Frameworks/vgmstream/vgmstream/src/meta/mups.c index fbfa5c65e..53f13549f 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/mups.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/mups.c @@ -6,30 +6,27 @@ /* MUPS - from Watermelon/HUCARD games (same programmer) [Pier Solar and the Great Architects (PC), Ghost Blade HD (PC/Switch)] */ VGMSTREAM* init_vgmstream_mups(STREAMFILE* sf) { VGMSTREAM* vgmstream = NULL; - STREAMFILE *temp_sf = NULL; + STREAMFILE* temp_sf = NULL; /* checks */ + if (!is_id32be(0x00,sf, "MUPS")) + goto fail; + /* mups: header id? * (extensionless): default? */ if (!check_extensions(sf, "mups,")) goto fail; - if (read_u32be(0x00,sf) != 0x4D555053) /* "MUPS" */ - goto fail; - if (read_u32be(0x08,sf) != 0x50737348) /* "PssH" */ + if (!is_id32be(0x08,sf, "PssH")) goto fail; /* just an Ogg with changed OggS/vorbis words (see streamfile) */ temp_sf = setup_mups_streamfile(sf, 0x08); if (!temp_sf) goto fail; -#ifdef VGM_USE_VORBIS vgmstream = init_vgmstream_ogg_vorbis(temp_sf); if (!vgmstream) goto fail; -#else - goto fail; -#endif close_streamfile(temp_sf); diff --git a/Frameworks/vgmstream/vgmstream/src/meta/mus_acm.c b/Frameworks/vgmstream/vgmstream/src/meta/mus_acm.c index 03c50233e..687045566 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/mus_acm.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/mus_acm.c @@ -11,11 +11,11 @@ #endif -static char** parse_mus(STREAMFILE *streamFile, int *out_file_count, int *out_loop_flag, int *out_loop_start_index, int *out_loop_end_index); +static char** parse_mus(STREAMFILE* sf, int *out_file_count, int *out_loop_flag, int *out_loop_start_index, int *out_loop_end_index); static void clean_mus(char** mus_filenames, int file_count); /* .MUS - playlist for InterPlay games [Planescape: Torment (PC), Baldur's Gate Enhanced Edition (PC)] */ -VGMSTREAM * init_vgmstream_mus_acm(STREAMFILE *streamFile) { +VGMSTREAM* init_vgmstream_mus_acm(STREAMFILE* sf) { VGMSTREAM * vgmstream = NULL; segmented_layout_data *data = NULL; @@ -27,11 +27,11 @@ VGMSTREAM * init_vgmstream_mus_acm(STREAMFILE *streamFile) { /* checks */ - if (!check_extensions(streamFile, "mus")) + if (!check_extensions(sf, "mus")) goto fail; /* get file paths from the .MUS text file */ - mus_filenames = parse_mus(streamFile, &segment_count, &loop_flag, &loop_start_index, &loop_end_index); + mus_filenames = parse_mus(sf, &segment_count, &loop_flag, &loop_start_index, &loop_end_index); if (!mus_filenames) goto fail; /* init layout */ @@ -40,24 +40,22 @@ VGMSTREAM * init_vgmstream_mus_acm(STREAMFILE *streamFile) { /* open each segment subfile */ for (i = 0; i < segment_count; i++) { - STREAMFILE* temp_streamFile = streamFile->open(streamFile, mus_filenames[i], STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!temp_streamFile) goto fail; + STREAMFILE* temp_sf = sf->open(sf, mus_filenames[i], STREAMFILE_DEFAULT_BUFFER_SIZE); + if (!temp_sf) goto fail; /* find .ACM type */ - switch(read_32bitBE(0x00,temp_streamFile)) { + switch(read_32bitBE(0x00,temp_sf)) { case 0x97280301: /* ACM header id [Planescape: Torment (PC)] */ - data->segments[i] = init_vgmstream_acm(temp_streamFile); + data->segments[i] = init_vgmstream_acm(temp_sf); break; -#ifdef VGM_USE_VORBIS case 0x4F676753: /* "OggS" [Planescape: Torment Enhanced Edition (PC)] */ - data->segments[i] = init_vgmstream_ogg_vorbis(temp_streamFile); + data->segments[i] = init_vgmstream_ogg_vorbis(temp_sf); break; -#endif default: data->segments[i] = NULL; break; } - close_streamfile(temp_streamFile); + close_streamfile(temp_sf); if (!data->segments[i]) goto fail; @@ -184,7 +182,7 @@ fail: return 1; } -static char** parse_mus(STREAMFILE *streamFile, int *out_file_count, int *out_loop_flag, int *out_loop_start_index, int *out_loop_end_index) { +static char** parse_mus(STREAMFILE *sf, int *out_file_count, int *out_loop_flag, int *out_loop_start_index, int *out_loop_end_index) { char** names = NULL; char filename[NAME_LENGTH]; @@ -204,7 +202,7 @@ static char** parse_mus(STREAMFILE *streamFile, int *out_file_count, int *out_lo /* read file name base */ - bytes_read = read_line(line, sizeof(line), mus_offset, streamFile, &line_ok); + bytes_read = read_line(line, sizeof(line), mus_offset, sf, &line_ok); if (!line_ok) goto fail; mus_offset += bytes_read; memcpy(name_base,line,sizeof(name_base)); @@ -217,7 +215,7 @@ static char** parse_mus(STREAMFILE *streamFile, int *out_file_count, int *out_lo } /* read track entry count */ - bytes_read = read_line(line, sizeof(line), mus_offset, streamFile, &line_ok); + bytes_read = read_line(line, sizeof(line), mus_offset, sf, &line_ok); if (!line_ok) goto fail; if (line[0] == '\0') goto fail; mus_offset += bytes_read; @@ -235,7 +233,7 @@ static char** parse_mus(STREAMFILE *streamFile, int *out_file_count, int *out_lo } dir_name[0]='\0'; - streamFile->get_name(streamFile,filename,sizeof(filename)); + sf->get_name(sf,filename,sizeof(filename)); concatn(sizeof(dir_name),dir_name,filename); /* find directory name for the directory contianing the MUS */ @@ -262,7 +260,7 @@ static char** parse_mus(STREAMFILE *streamFile, int *out_file_count, int *out_lo for (i = 0; i < file_count; i++) { int fields_matched; - bytes_read = read_line(line,sizeof(line), mus_offset, streamFile, &line_ok); + bytes_read = read_line(line,sizeof(line), mus_offset, sf, &line_ok); if (!line_ok) goto fail; mus_offset += bytes_read; @@ -308,13 +306,13 @@ static char** parse_mus(STREAMFILE *streamFile, int *out_file_count, int *out_lo concatn(NAME_LENGTH,names[i],name); concatn(NAME_LENGTH,names[i],".ACM"); - if (!exists(names[i],streamFile)) { + if (!exists(names[i],sf)) { /* We can't test for the directory until we have a file name * to look for, so we do it here with the first file that seems to * be in a subdirectory */ if (subdir_name[0]=='\0') { - if (find_directory_name(name_base, dir_name, sizeof(subdir_name), subdir_name, name, filename, streamFile)) + if (find_directory_name(name_base, dir_name, sizeof(subdir_name), subdir_name, name, filename, sf)) goto fail; } @@ -325,7 +323,7 @@ static char** parse_mus(STREAMFILE *streamFile, int *out_file_count, int *out_lo concatn(NAME_LENGTH,names[i],name); concatn(NAME_LENGTH,names[i],".ACM"); - if (!exists(names[i],streamFile)) goto fail; + if (!exists(names[i],sf)) goto fail; } } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/nds_strm.c b/Frameworks/vgmstream/vgmstream/src/meta/nds_strm.c index cbd534f5a..64befb423 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/nds_strm.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/nds_strm.c @@ -2,41 +2,43 @@ #include "../util.h" /* STRM - common Nintendo NDS streaming format */ -VGMSTREAM * init_vgmstream_nds_strm(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; +VGMSTREAM* init_vgmstream_nds_strm(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; off_t start_offset; - int channel_count, loop_flag, codec; + int channels, loop_flag, codec, sample_rate; /* checks */ - if (!check_extensions(streamFile, "strm")) + if (!is_id32be(0x00,sf, "STRM")) goto fail; - if (read_32bitBE(0x00,streamFile) != 0x5354524D) /* "STRM" */ - goto fail; - if (read_32bitBE(0x04,streamFile) != 0xFFFE0001 && /* Old Header Check */ - (read_32bitBE(0x04,streamFile) != 0xFEFF0001)) /* Some newer games have a new flag */ + if (!check_extensions(sf, "strm")) goto fail; - if (read_32bitBE(0x10,streamFile) != 0x48454144 && /* "HEAD" */ - read_32bitLE(0x14,streamFile) != 0x50) /* 0x50-sized head is all I've seen */ + /* BOM check? */ + if (read_u32be(0x04,sf) != 0xFFFE0001 && + read_u32be(0x04,sf) != 0xFEFF0001) /* newer games? */ goto fail; - codec = read_8bit(0x18,streamFile); - loop_flag = read_8bit(0x19,streamFile); - channel_count = read_8bit(0x1a,streamFile); - if (channel_count > 2) goto fail; + if (!is_id32be(0x10,sf, "HEAD") && + read_u32le(0x14,sf) != 0x50) + goto fail; - start_offset = read_32bitLE(0x28,streamFile); + codec = read_u8(0x18,sf); + loop_flag = read_u8(0x19,sf); + sample_rate = read_u16le(0x1c,sf); + channels = read_u8(0x1a,sf); + if (channels > 2) goto fail; + start_offset = read_u32le(0x28,sf); /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); + vgmstream = allocate_vgmstream(channels, loop_flag); if (!vgmstream) goto fail; - vgmstream->sample_rate = (uint16_t)read_16bitLE(0x1c,streamFile); - vgmstream->num_samples = read_32bitLE(0x24,streamFile); - vgmstream->loop_start_sample = read_32bitLE(0x20,streamFile); + vgmstream->sample_rate = sample_rate; + vgmstream->num_samples = read_32bitLE(0x24,sf); + vgmstream->loop_start_sample = read_32bitLE(0x20,sf); vgmstream->loop_end_sample = vgmstream->num_samples; vgmstream->meta_type = meta_STRM; @@ -55,11 +57,11 @@ VGMSTREAM * init_vgmstream_nds_strm(STREAMFILE *streamFile) { goto fail; } vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = read_32bitLE(0x30,streamFile); - vgmstream->interleave_last_block_size = read_32bitLE(0x38,streamFile); + vgmstream->interleave_block_size = read_32bitLE(0x30,sf); + vgmstream->interleave_last_block_size = read_32bitLE(0x38,sf); - if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + if (!vgmstream_open_stream(vgmstream, sf, start_offset)) goto fail; return vgmstream; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/nwav.c b/Frameworks/vgmstream/vgmstream/src/meta/nwav.c index a9557722d..62855a0d0 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/nwav.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/nwav.c @@ -2,37 +2,35 @@ #include "../coding/coding.h" /* NWAV - from Chunsoft games [Fuurai no Shiren Gaiden: Onnakenshi Asuka Kenzan! (PC)] */ -VGMSTREAM * init_vgmstream_nwav(STREAMFILE *sf) { - VGMSTREAM * vgmstream = NULL; +VGMSTREAM* init_vgmstream_nwav(STREAMFILE* sf) { off_t start_offset; /* checks */ + if (!is_id32be(0x00,sf, "NWAV")) + goto fail; /* .nwav: header id (no filenames in bigfiles) */ - if ( !check_extensions(sf,"nwav") ) - goto fail; - if (read_32bitBE(0x00,sf) != 0x4E574156) /* "NWAV" */ + if (!check_extensions(sf,"nwav,") ) goto fail; -#ifdef VGM_USE_VORBIS { ogg_vorbis_meta_info_t ovmi = {0}; int channels; /* 0x04: version? */ /* 0x08: crc? */ - ovmi.stream_size = read_32bitLE(0x0c, sf); - ovmi.loop_end = read_32bitLE(0x10, sf); /* num_samples, actually */ + ovmi.stream_size = read_u32le(0x0c, sf); + ovmi.loop_end = read_u32le(0x10, sf); /* num_samples, actually */ /* 0x14: sample rate */ /* 0x18: bps? (16) */ - channels = read_8bit(0x19, sf); - start_offset = read_16bitLE(0x1a, sf); + channels = read_u8(0x19, sf); + start_offset = read_u16le(0x1a, sf); - ovmi.loop_flag = read_16bitLE(0x1c, sf) != 0; /* loop count? -1 = loops */ + ovmi.loop_flag = read_u16le(0x1c, sf) != 0; /* loop count? -1 = loops */ /* 0x1e: always 2? */ /* 0x20: always 1? */ - ovmi.loop_start = read_32bitLE(0x24, sf); + ovmi.loop_start = read_u32le(0x24, sf); /* 0x28: always 1? */ /* 0x2a: always 1? */ /* 0x2c: always null? */ @@ -43,15 +41,9 @@ VGMSTREAM * init_vgmstream_nwav(STREAMFILE *sf) { ovmi.loop_start = ovmi.loop_start / sizeof(int16_t) / channels; ovmi.loop_end = ovmi.loop_end / sizeof(int16_t) / channels; - vgmstream = init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi); + return init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi); } -#else - goto fail; -#endif - - return vgmstream; fail: - close_vgmstream(vgmstream); return NULL; } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ogg_vorbis.c b/Frameworks/vgmstream/vgmstream/src/meta/ogg_vorbis.c index beb134158..fea8a905f 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ogg_vorbis.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ogg_vorbis.c @@ -1,4 +1,3 @@ -#ifdef VGM_USE_VORBIS #include #include #include "meta.h" @@ -6,6 +5,28 @@ #include "ogg_vorbis_streamfile.h" +#ifdef VGM_USE_VORBIS +static VGMSTREAM* _init_vgmstream_ogg_vorbis(STREAMFILE* sf); +static VGMSTREAM* _init_vgmstream_ogg_vorbis_config(STREAMFILE* sf, off_t start, const ogg_vorbis_meta_info_t* ovmi); +#endif + +VGMSTREAM* init_vgmstream_ogg_vorbis(STREAMFILE* sf) { +#ifdef VGM_USE_VORBIS + return _init_vgmstream_ogg_vorbis(sf); +#else + return NULL; +#endif +} + +VGMSTREAM* init_vgmstream_ogg_vorbis_config(STREAMFILE* sf, off_t start, const ogg_vorbis_meta_info_t* ovmi) { +#ifdef VGM_USE_VORBIS + return _init_vgmstream_ogg_vorbis_config(sf, start, ovmi); +#else + return NULL; +#endif +} + +#ifdef VGM_USE_VORBIS static void um3_ogg_decryption_callback(void* ptr, size_t size, size_t nmemb, void* datasource) { uint8_t *ptr8 = ptr; size_t bytes_read = size * nmemb; @@ -110,8 +131,8 @@ static const uint32_t xiph_mappings[] = { }; -/* Ogg Vorbis, may contain loop comments */ -VGMSTREAM* init_vgmstream_ogg_vorbis(STREAMFILE* sf) { +/* Ogg Vorbis - standard .ogg with (possibly) loop comments/metadata */ +static VGMSTREAM* _init_vgmstream_ogg_vorbis(STREAMFILE* sf) { VGMSTREAM* vgmstream = NULL; STREAMFILE* temp_sf = NULL; ogg_vorbis_io_config_data cfg = {0}; @@ -416,7 +437,7 @@ VGMSTREAM* init_vgmstream_ogg_vorbis(STREAMFILE* sf) { ovmi.meta_type = meta_OGG_VORBIS; } - vgmstream = init_vgmstream_ogg_vorbis_config(temp_sf != NULL ? temp_sf : sf, start_offset, &ovmi); + vgmstream = _init_vgmstream_ogg_vorbis_config(temp_sf != NULL ? temp_sf : sf, start_offset, &ovmi); close_streamfile(temp_sf); return vgmstream; @@ -426,7 +447,7 @@ fail: return NULL; } -VGMSTREAM* init_vgmstream_ogg_vorbis_config(STREAMFILE* sf, off_t start, const ogg_vorbis_meta_info_t* ovmi) { +static VGMSTREAM* _init_vgmstream_ogg_vorbis_config(STREAMFILE* sf, off_t start, const ogg_vorbis_meta_info_t* ovmi) { VGMSTREAM* vgmstream = NULL; ogg_vorbis_codec_data* data = NULL; ogg_vorbis_io io = {0}; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ogv_3rdeye.c b/Frameworks/vgmstream/vgmstream/src/meta/ogv_3rdeye.c index 553d5109c..20f3be375 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ogv_3rdeye.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ogv_3rdeye.c @@ -3,15 +3,14 @@ /* OGV - .ogg container (not related to ogv video) [Bloody Rondo (PC)] */ VGMSTREAM* init_vgmstream_ogv_3rdeye(STREAMFILE* sf) { - VGMSTREAM* vgmstream = NULL; - off_t subfile_offset, subfile_size; + uint32_t subfile_offset, subfile_size; /* checks */ - if (!check_extensions(sf,"ogv")) - goto fail; if (!is_id32be(0x00,sf, "OGV\0")) goto fail; + if (!check_extensions(sf,"ogv")) + goto fail; /* 0x04: PCM size */ subfile_size = read_u32le(0x08, sf); @@ -20,21 +19,15 @@ VGMSTREAM* init_vgmstream_ogv_3rdeye(STREAMFILE* sf) { /* no loops (files bgm does full loops but sfx doesn't) */ -#ifdef VGM_USE_VORBIS { ogg_vorbis_meta_info_t ovmi = {0}; ovmi.meta_type = meta_OGV_3RDEYE; ovmi.stream_size = subfile_size; - vgmstream = init_vgmstream_ogg_vorbis_config(sf, subfile_offset, &ovmi); + return init_vgmstream_ogg_vorbis_config(sf, subfile_offset, &ovmi); } -#else - goto fail; -#endif - return vgmstream; fail: - close_vgmstream(vgmstream); return NULL; } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/psb.c b/Frameworks/vgmstream/vgmstream/src/meta/psb.c index bba607ce0..37bb9b9ff 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/psb.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/psb.c @@ -132,15 +132,27 @@ VGMSTREAM* init_vgmstream_psb(STREAMFILE* sf) { switch(psb.codec) { case PCM: + if (psb.layers > 1) { + /* somehow R offset can go before L, use layered */ + vgmstream->layout_data = build_layered_psb(sf, &psb); + if (!vgmstream->layout_data) goto fail; + vgmstream->layout_type = layout_layered; + + if (!vgmstream->num_samples) + vgmstream->num_samples = pcm_bytes_to_samples(psb.stream_size[0], 1, psb.bps); + } + else { + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = psb.block_size / psb.channels; + if (!vgmstream->num_samples) + vgmstream->num_samples = pcm_bytes_to_samples(psb.stream_size[0], psb.channels, psb.bps); + } + switch(psb.bps) { case 16: vgmstream->coding_type = coding_PCM16LE; break; /* Legend of Mana (PC), Namco Museum Archives Vol.1 (PC) */ case 24: vgmstream->coding_type = coding_PCM24LE; break; /* Legend of Mana (PC) */ default: goto fail; } - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = psb.block_size / psb.channels; - if (!vgmstream->num_samples) - vgmstream->num_samples = pcm_bytes_to_samples(psb.stream_size[0], psb.channels, psb.bps); break; case MSADPCM: /* [Senxin Aleste (AC)] */ @@ -235,7 +247,7 @@ static segmented_layout_data* build_segmented_psb_opus(STREAMFILE* sf, psb_heade uint32_t samples[] = {psb->intro_samples, psb->body_samples}; uint32_t skips[] = {0, psb->skip_samples}; - /* intro + body (looped songs) or just body (standard songs) + /* intro + body (looped songs) or just body (standard songs) in full loops intro is 0 samples with a micro 1-frame opus [Nekopara (Switch)] */ if (offsets[0] && samples[0]) segment_count++; @@ -279,6 +291,21 @@ fail: return NULL; } + +static VGMSTREAM* try_init_vgmstream(STREAMFILE* sf, init_vgmstream_t init_vgmstream, const char* extension, uint32_t offset, uint32_t size) { + STREAMFILE* temp_sf = NULL; + VGMSTREAM* v = NULL; + + temp_sf = setup_subfile_streamfile(sf, offset, size, extension); + if (!temp_sf) goto fail; + + v = init_vgmstream(temp_sf); + close_streamfile(temp_sf); + return v; +fail: + return NULL; +} + static layered_layout_data* build_layered_psb(STREAMFILE* sf, psb_header_t* psb) { layered_layout_data* data = NULL; int i; @@ -289,25 +316,39 @@ static layered_layout_data* build_layered_psb(STREAMFILE* sf, psb_header_t* psb) if (!data) goto fail; for (i = 0; i < psb->layers; i++) { - STREAMFILE* temp_sf = NULL; - VGMSTREAM* (*init_vgmstream)(STREAMFILE* sf) = NULL; - const char* extension = NULL; - switch (psb->codec) { - case DSP: - extension = "adpcm"; - init_vgmstream = init_vgmstream_ngc_dsp_std_le; + case PCM: { + VGMSTREAM* v = allocate_vgmstream(1, 0); + if (!v) goto fail; + + data->layers[i] = v; + + v->sample_rate = psb->sample_rate; + v->num_samples = psb->num_samples; + + switch(psb->bps) { + case 16: v->coding_type = coding_PCM16LE; break; + case 24: v->coding_type = coding_PCM24LE; break; + default: goto fail; + } + v->layout_type = layout_none; + if (!v->num_samples) + v->num_samples = pcm_bytes_to_samples(psb->stream_size[i], 1, psb->bps); + + if (!vgmstream_open_stream(v, sf, psb->stream_offset[i])) + goto fail; break; + } + + case DSP: + data->layers[i] = try_init_vgmstream(sf, init_vgmstream_ngc_dsp_std_le, "adpcm", psb->stream_offset[i], psb->stream_size[i]); + if (!data->layers[i]) goto fail; + break; + default: + VGM_LOG("psb: layer not implemented\n"); goto fail; } - - temp_sf = setup_subfile_streamfile(sf, psb->stream_offset[i], psb->stream_size[i], extension); - if (!temp_sf) goto fail; - - data->layers[i] = init_vgmstream(temp_sf); - close_streamfile(temp_sf); - if (!data->layers[i]) goto fail; } /* setup layered VGMSTREAMs */ @@ -332,9 +373,9 @@ static int prepare_fmt(STREAMFILE* sf, psb_header_t* psb) { psb->format = read_u16be(offset + 0x00,sf); psb->channels = read_u16be(offset + 0x02,sf); psb->sample_rate = read_u32be(offset + 0x04,sf); - xma2_parse_fmt_chunk_extra(sf, - offset, - &psb->loop_flag, + xma2_parse_fmt_chunk_extra(sf, + offset, + &psb->loop_flag, &psb->num_samples, &psb->loop_start, &psb->loop_end, @@ -347,7 +388,7 @@ static int prepare_fmt(STREAMFILE* sf, psb_header_t* psb) { psb->block_size = read_u16le(offset + 0x0c,sf); psb->bps = read_u16le(offset + 0x0e,sf); /* 0x10+ varies */ - + switch(psb->format) { case 0x0002: if (!msadpcm_check_coefs(sf, offset + 0x14)) @@ -356,7 +397,7 @@ static int prepare_fmt(STREAMFILE* sf, psb_header_t* psb) { default: break; } - + } return 1; @@ -392,11 +433,12 @@ static int prepare_codec(STREAMFILE* sf, psb_header_t* psb) { /* try console strings */ if (!spec) goto fail; - + if (strcmp(spec, "nx") == 0) { if (!ext) goto fail; - + + /* common, multichannel */ if (strcmp(ext, ".opus") == 0) { psb->codec = OPUSNX; @@ -409,12 +451,22 @@ static int prepare_codec(STREAMFILE* sf, psb_header_t* psb) { return 1; } + /* Legend of Mana (Switch), layered */ if (strcmp(ext, ".adpcm") == 0) { psb->codec = DSP; psb->channels = psb->layers; return 1; } + + /* Castlevania Advance Collection (Switch), layered */ + if (strcmp(ext, ".p16") == 0) { + psb->codec = PCM; + psb->bps = 16; + + psb->channels = psb->layers; + return 1; + } } if (strcmp(spec, "ps3") == 0) { @@ -477,7 +529,7 @@ static int prepare_psb_extra(STREAMFILE* sf, psb_header_t* psb) { goto fail; return 1; fail: - return 0; + return 0; } @@ -488,7 +540,7 @@ fail: * - body/channelCount/ext/intro/loop/samprate [Legend of Mana (Switch)] * - body: data/sampleCount/skipSampleCount, intro: data/sampleCount * - data/dpds/fmt/wav/loop - * - pan: array [N.0 .. 0.N] (when N layers, in practice just a wonky L/R definition) + * - pan: array [N.0 .. 0.N] (when N layers, in practice just a wonky L/R definition) */ static int parse_psb_channels(psb_header_t* psb, psb_node_t* nchans) { int i; @@ -584,7 +636,7 @@ static int parse_psb_channels(psb_header_t* psb, psb_node_t* nchans) { }; } - /* background: false? + /* background: false? */ break; @@ -659,7 +711,7 @@ fail: * - "archData": (main audio part, varies per game/platform/codec) * - "device": ? * ... - * - (voice name N): ... + * - (voice name N): ... * From decompilations, audio code reads common keys up to "archData", then depends on game (not unified). * Keys are (seemingly) stored in text order. */ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/riff.c b/Frameworks/vgmstream/vgmstream/src/meta/riff.c index c83c48020..5e9a4db70 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/riff.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/riff.c @@ -215,7 +215,13 @@ static int read_fmt(int big_endian, STREAMFILE* sf, off_t offset, riff_fmt_chunk break; #ifdef VGM_USE_VORBIS - case 0x6771: /* Ogg Vorbis (mode 3+) */ + //case 0x674f: /* Ogg Vorbis (mode 1) */ + //case 0x6750: /* Ogg Vorbis (mode 2) */ + //case 0x6751: /* Ogg Vorbis (mode 3) */ + case 0x676f: /* Ogg Vorbis (mode 1+) [Only One 2 (PC)] */ + //case 0x6770: /* Ogg Vorbis (mode 2+) */ + case 0x6771: /* Ogg Vorbis (mode 3+) [Liar-soft games] */ + /* vorbis.acm codecs (official-ish, "+" = CBR-style modes?) */ fmt->coding_type = coding_OGG_VORBIS; break; #endif @@ -233,7 +239,7 @@ static int read_fmt(int big_endian, STREAMFILE* sf, off_t offset, riff_fmt_chunk (read_u16 (offset+0x26,sf)); uint32_t guid3 = read_u32be(offset+0x28,sf); uint32_t guid4 = read_u32be(offset+0x2c,sf); - //;VGM_LOG("RIFF: guid %08x %08x %08x %08x\n", guid1, guid2, guid3, guid4); + //;VGM_LOG("riff: guid %08x %08x %08x %08x\n", guid1, guid2, guid3, guid4); /* PCM GUID (0x00000001,0000,0010,80,00,00,AA,00,38,9B,71) */ if (guid1 == 0x00000001 && guid2 == 0x00000010 && guid3 == 0x800000AA && guid4 == 0x00389B71) { @@ -280,7 +286,7 @@ static int read_fmt(int big_endian, STREAMFILE* sf, off_t offset, riff_fmt_chunk default: /* FFmpeg may play it */ - //vgm_logi("WWISE: unknown codec 0x%04x (report)\n", fmt->format); + //vgm_logi("RIFF: unknown codec 0x%04x (report)\n", fmt->format); goto fail; } @@ -318,7 +324,10 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) { off_t mwv_ctrl_offset = -1; - /* check extension */ + /* checks*/ + if (!is_id32be(0x00,sf,"RIFF")) + goto fail; + /* .lwav: to avoid hijacking .wav * .xwav: fake for Xbox games (not needed anymore) * .da: The Great Battle VI (PS1) @@ -355,21 +364,19 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) { goto fail; } - /* check header */ - if (!is_id32be(0x00,sf,"RIFF")) - goto fail; + riff_size = read_u32le(0x04,sf); + if (!is_id32be(0x08,sf, "WAVE")) goto fail; - riff_size = read_u32le(0x04,sf); file_size = get_streamfile_size(sf); /* some games have wonky sizes, selectively fix to catch bad rips and new mutations */ if (file_size != riff_size + 0x08) { uint16_t codec = read_u16le(0x14,sf); - if (codec == 0x6771 && riff_size + 0x08 + 0x01 == file_size) - riff_size += 0x01; /* [Shikkoku no Sharnoth (PC)] (Sony Sound Forge?) */ + if ((codec & 0xFF00) == 0x6700 && riff_size + 0x08 + 0x01 == file_size) + riff_size += 0x01; /* [Shikkoku no Sharnoth (PC), Only One 2 (PC)] (Sony Sound Forge?) */ else if (codec == 0x0069 && riff_size == file_size) riff_size -= 0x08; /* [Dynasty Warriors 3 (Xbox), BloodRayne (Xbox)] */ @@ -422,6 +429,7 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) { /* check for truncated RIFF */ if (file_size != riff_size + 0x08) { vgm_logi("RIFF: wrong expected size (report/re-rip?)\n"); + VGM_LOG("riff: file_size = %x, riff_size+8 = %x\n", file_size, riff_size + 0x08); /* don't log to user */ goto fail; } @@ -774,8 +782,9 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) { #endif #ifdef VGM_USE_VORBIS case coding_OGG_VORBIS: { - /* special handling of Liar-soft's buggy RIFF+Ogg made with Soundforge [Shikkoku no Sharnoth (PC)] */ - STREAMFILE *temp_sf = setup_riff_ogg_streamfile(sf, start_offset, data_size); + /* special handling of Liar-soft's buggy RIFF+Ogg made with Soundforge/vorbis.acm [Shikkoku no Sharnoth (PC)], + * and rarely other devs, not always buggy [Kirara Kirara NTR (PC), No One 2 (PC)] */ + STREAMFILE* temp_sf = setup_riff_ogg_streamfile(sf, start_offset, data_size); if (!temp_sf) goto fail; vgmstream->codec_data = init_ogg_vorbis(temp_sf, 0x00, get_streamfile_size(temp_sf), NULL); @@ -983,13 +992,13 @@ VGMSTREAM* init_vgmstream_rifx(STREAMFILE* sf) { int FormatChunkFound = 0, DataChunkFound = 0; - /* check extension, case insensitive */ + /* checks */ + if (!is_id32be(0x00,sf, "RIFX")) + goto fail; + if (!check_extensions(sf, "wav,lwav")) goto fail; - /* check header */ - if (!is_id32be(0x00,sf, "RIFX")) - goto fail; if (!is_id32be(0x08,sf, "WAVE")) goto fail; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/riff_ogg_streamfile.h b/Frameworks/vgmstream/vgmstream/src/meta/riff_ogg_streamfile.h index 35ee7b167..ad92ed559 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/riff_ogg_streamfile.h +++ b/Frameworks/vgmstream/vgmstream/src/meta/riff_ogg_streamfile.h @@ -3,22 +3,22 @@ #include "deblock_streamfile.h" typedef struct { - off_t patch_offset; + uint32_t patch_offset; } riff_ogg_io_data; -static size_t riff_ogg_io_read(STREAMFILE *sf, uint8_t *dest, off_t offset, size_t length, riff_ogg_io_data* data) { - size_t bytes = read_streamfile(dest, offset, length, sf); +static size_t riff_ogg_io_read(STREAMFILE* sf, uint8_t* dst, uint32_t offset, size_t length, riff_ogg_io_data* data) { + size_t bytes = read_streamfile(dst, offset, length, sf); /* has garbage init Oggs pages, patch bad flag */ if (data->patch_offset && data->patch_offset >= offset && data->patch_offset < offset + bytes) { - VGM_ASSERT(dest[data->patch_offset - offset] != 0x02, "RIFF Ogg: bad patch offset at %lx\n", data->patch_offset); - dest[data->patch_offset - offset] = 0x00; + VGM_ASSERT(dst[data->patch_offset - offset] != 0x02, "RIFF Ogg: bad patch offset at %x\n", data->patch_offset); + dst[data->patch_offset - offset] = 0x00; } return bytes; } -static size_t ogg_get_page(uint8_t *buf, size_t bufsize, off_t offset, STREAMFILE *sf) { +static size_t ogg_get_page(uint8_t* buf, size_t bufsize, uint32_t offset, STREAMFILE* sf) { size_t segments, bytes, page_size; int i; @@ -43,8 +43,8 @@ fail: } /* patches Ogg with weirdness */ -static STREAMFILE* setup_riff_ogg_streamfile(STREAMFILE *sf, off_t start, size_t size) { - off_t patch_offset = 0; +static STREAMFILE* setup_riff_ogg_streamfile(STREAMFILE* sf, uint32_t start, size_t size) { + uint32_t patch_offset = 0; size_t real_size = size; uint8_t buf[0x1000]; @@ -52,11 +52,11 @@ static STREAMFILE* setup_riff_ogg_streamfile(STREAMFILE *sf, off_t start, size_t /* initial page flag is repeated and causes glitches in decoders, find bad offset */ //todo callback could patch on-the-fly by analyzing all "OggS", but is problematic due to arbitrary offsets { - off_t offset = start; + uint32_t offset = start; size_t page_size; - off_t offset_limit = start + size; /* usually in the first 0x3000 but can be +0x100000 */ + uint32_t offset_limit = start + size; /* usually in the first 0x3000 but can be +0x100000 */ //todo this doesn't seem to help much - STREAMFILE *temp_sf = reopen_streamfile(sf, 0x100); /* use small-ish sf to avoid reading the whole thing */ + STREAMFILE* temp_sf = reopen_streamfile(sf, 0x100); /* use small-ish sf to avoid reading the whole thing */ /* first page is ok */ page_size = ogg_get_page(buf, sizeof(buf), offset, temp_sf); @@ -66,7 +66,7 @@ static STREAMFILE* setup_riff_ogg_streamfile(STREAMFILE *sf, off_t start, size_t page_size = ogg_get_page(buf, sizeof(buf), offset, temp_sf); if (page_size == 0) break; - if (get_u32be(buf + 0x00) != 0x4f676753) /* "OggS" */ + if (get_u32be(buf + 0x00) != get_id32be("OggS")) break; if (get_u16be(buf + 0x04) == 0x0002) { /* start page flag */ @@ -80,8 +80,9 @@ static STREAMFILE* setup_riff_ogg_streamfile(STREAMFILE *sf, off_t start, size_t close_streamfile(temp_sf); - if (patch_offset == 0) - return NULL; + /* no need to patch initial flag */ + //if (patch_offset == 0) + // return NULL; } /* has a bunch of padding(?) pages at the end with no data nor flag that confuse decoders, find actual end */ @@ -89,14 +90,14 @@ static STREAMFILE* setup_riff_ogg_streamfile(STREAMFILE *sf, off_t start, size_t size_t chunk_size = sizeof(buf); /* not worth testing more */ size_t max_size = size; size_t pos; - off_t read_offset = start + size - chunk_size; + uint32_t read_offset = start + size - chunk_size; pos = read_streamfile(buf, read_offset, chunk_size, sf); if (read_offset < 0 || pos <= 0x1a) return NULL; pos -= 0x1a; /* at least one OggS page */ while (pos > 0) { - if (get_u32be(buf + pos + 0x00) == 0x4f676753) { /* "OggS" */ + if (get_u32be(buf + pos + 0x00) == get_id32be("OggS")) { if (get_u16be(buf + pos + 0x04) == 0x0004) { /* last page flag is ok */ real_size = max_size; @@ -112,7 +113,7 @@ static STREAMFILE* setup_riff_ogg_streamfile(STREAMFILE *sf, off_t start, size_t /* actual custom streamfile init */ { - STREAMFILE *new_sf = NULL; + STREAMFILE* new_sf = NULL; riff_ogg_io_data io_data = {0}; io_data.patch_offset = patch_offset; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/sps_n1.c b/Frameworks/vgmstream/vgmstream/src/meta/sps_n1.c index 7a55020d9..eed3d11c8 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/sps_n1.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/sps_n1.c @@ -12,8 +12,8 @@ VGMSTREAM* init_vgmstream_sps_n1(STREAMFILE* sf) { off_t subfile_offset; size_t subfile_size; - VGMSTREAM* (*init_vgmstream_subfile)(STREAMFILE*) = NULL; - const char* extension; + init_vgmstream_t init_vgmstream = NULL; + const char* extension = NULL; uint32_t (*read_u32)(off_t,STREAMFILE*); uint16_t (*read_u16)(off_t,STREAMFILE*); @@ -38,12 +38,12 @@ VGMSTREAM* init_vgmstream_sps_n1(STREAMFILE* sf) { switch(type) { case 1: - init_vgmstream_subfile = init_vgmstream_vag; + init_vgmstream = init_vgmstream_vag; extension = "vag"; break; case 2: - init_vgmstream_subfile = init_vgmstream_riff; + init_vgmstream = init_vgmstream_riff; extension = "at3"; break; @@ -59,7 +59,7 @@ VGMSTREAM* init_vgmstream_sps_n1(STREAMFILE* sf) { temp_sf = setup_subfile_streamfile(sf, subfile_offset, subfile_size, extension); if (!temp_sf) goto fail; - vgmstream = init_vgmstream_subfile(temp_sf); + vgmstream = init_vgmstream(temp_sf); if (!vgmstream) goto fail; vgmstream->sample_rate = sample_rate; /* .vag header doesn't match */ @@ -81,7 +81,7 @@ VGMSTREAM* init_vgmstream_sps_n1_segmented(STREAMFILE* sf) { int loop_flag, type, sample_rate; int i, segment; - VGMSTREAM* (*init_vgmstream_subfile)(STREAMFILE*) = NULL; + init_vgmstream_t init_vgmstream = NULL; const char* extension; segmented_layout_data* data = NULL; int segment_count, loop_start_segment, loop_end_segment; @@ -101,15 +101,13 @@ VGMSTREAM* init_vgmstream_sps_n1_segmented(STREAMFILE* sf) { /* 0x0c: num_samples (slightly smaller than added samples?) */ switch(type) { - #ifdef VGM_USE_VORBIS case 7: - init_vgmstream_subfile = init_vgmstream_ogg_vorbis; + init_vgmstream = init_vgmstream_ogg_vorbis; extension = "ogg"; break; - #endif case 9: - init_vgmstream_subfile = init_vgmstream_opus_std; + init_vgmstream = init_vgmstream_opus_std; extension = "opus"; break; @@ -155,7 +153,7 @@ VGMSTREAM* init_vgmstream_sps_n1_segmented(STREAMFILE* sf) { temp_sf = setup_subfile_streamfile(sf, segment_offset,segment_size, extension); if (!temp_sf) goto fail; - data->segments[segment] = init_vgmstream_subfile(temp_sf); + data->segments[segment] = init_vgmstream(temp_sf); close_streamfile(temp_sf); if (!data->segments[segment]) goto fail; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/str_wav.c b/Frameworks/vgmstream/vgmstream/src/meta/str_wav.c index f4181837f..6c32cbaad 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/str_wav.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/str_wav.c @@ -213,11 +213,6 @@ static int parse_header(STREAMFILE* sf_h, STREAMFILE* sf_b, strwav_header* strwa * table entries don't need to match (table2 may be slightly bigger) */ -//breaking ta rules full test again, fuse with Pac-Man World 3 -//same on xbox and pc -//same with zapper + pw3 gc - - //todo loop start/end values may be off for some headers /* Fuzion Frenzy (Xbox)[2001] wma */ @@ -251,7 +246,7 @@ static int parse_header(STREAMFILE* sf_h, STREAMFILE* sf_b, strwav_header* strwa /* Cubix Robots for Everyone: Showdown (GC)[2003] */ if ( read_u32be(0x04,sf_h) == 0x00000900 && read_u32be(0x0c,sf_h) != header_size && - read_u32le(0x24,sf_h) != 0 && + read_u32be(0x24,sf_h) != 0 && read_u32be(0x24,sf_h) == read_u32be(0x90,sf_h) && /* sample rate repeat */ read_u32be(0xa0,sf_h) == header_size /* ~0x3C0 */ ) { @@ -367,9 +362,11 @@ static int parse_header(STREAMFILE* sf_h, STREAMFILE* sf_b, strwav_header* strwa return 1; } - /* Zapper: One Wicked Cricket! (GC)[2005] */ + /* Zapper: One Wicked Cricket! Beta (GC)[2002] */ + /* Zapper: One Wicked Cricket! (GC)[2002] */ if ( read_u32be(0x04,sf_h) == 0x00000900 && read_u32be(0x24,sf_h) == read_u32be(0xB0,sf_h) && /* sample rate repeat */ + read_u32be(0x88,sf_h) != 0 && read_u32le(0xc0,sf_h) == header_size /* LE! */ ) { /* 0x08: null */ @@ -399,10 +396,36 @@ static int parse_header(STREAMFILE* sf_h, STREAMFILE* sf_b, strwav_header* strwa return 1; } + /* Zapper: One Wicked Cricket! Beta (PS2)[2002] */ + if ( read_u32be(0x04,sf_h) == 0x00000900 && + read_u32le(0x2c,sf_h) == 44100 && /* sample rate */ + read_u32le(0x70,sf_h) == 0 && /* sample rate repeat? */ + header_size == 0x78 + ) { + /* 0x08: null */ + /* 0x0c: hashname */ + /* 0x28: loop start? */ + strwav->sample_rate = read_s32le(0x2c,sf_h); + /* 0x30: number of 0x800 sectors */ + strwav->flags = read_u32le(0x34,sf_h); + strwav->num_samples = read_s32le(0x5c,sf_h); + strwav->tracks = read_s32le(0x60,sf_h); + + strwav->loop_start = 0; + strwav->loop_end = 0; + + strwav->codec = PSX; + strwav->interleave = strwav->tracks > 1 ? 0x8000 : 0x8000; + //todo: tracks are stereo blocks of size 0x20000*tracks, containing 4 interleaves of 0x8000: + // | 1 2 1 2 | 3 4 3 4 | 5 6 5 6 | 1 2 1 2 | 3 4 3 4 | 5 6 5 6 | ... + ;VGM_LOG("STR+WAV: header ZPb (PS2)\n"); + return 1; + } + + /* Zapper: One Wicked Cricket! (PS2)[2002] */ /* The Fairly OddParents - Breakin' da Rules (PS2)[2003] */ /* The Fairly OddParents! - Shadow Showdown (PS2)[2004] */ /* Bad Boys II (PS2)[2004] */ - /* Zapper: One Wicked Cricket! (PS2)[2005] */ if ((read_u32be(0x04,sf_h) == 0x00000800 || /* BB2 */ read_u32be(0x04,sf_h) == 0x00000900) && /* FOP, ZP */ read_u32le(0x24,sf_h) == read_u32le(0x70,sf_h) && /* sample rate repeat */ @@ -456,7 +479,62 @@ static int parse_header(STREAMFILE* sf_h, STREAMFILE* sf_b, strwav_header* strwa return 1; } - /* Zapper: One Wicked Cricket! (PC)[2005] */ + /* Zapper: One Wicked Cricket! Beta (Xbox)[2002] */ + if ( read_u32be(0x04,sf_h) == 0x00000900 && + read_u32le(0x0c,sf_h) != header_size && + read_u32le(0x24,sf_h) != 0 && + read_u32le(0x24,sf_h) == read_u32le(0x90,sf_h) && /* sample rate repeat */ + read_u32le(0xa0,sf_h) == header_size /* ~0xC0 */ + ) { + /* 0x08: null */ + /* 0x0c: hashname */ + strwav->num_samples = read_s32le(0x20,sf_h); + strwav->sample_rate = read_s32le(0x24,sf_h); + /* 0x28: 16 bps */ + strwav->flags = read_u32le(0x2c,sf_h); + strwav->loop_start = read_s32le(0x38,sf_h); + strwav->tracks = read_s32le(0x50,sf_h); + /* 0x58: number of chunks? */ + /* 0x90: sample rate 2 */ + /* 0xb8: total frames? */ + + strwav->loop_end = strwav->num_samples; + + strwav->codec = XBOX; + strwav->interleave = strwav->tracks > 1 ? 0xD800/2 : 0xD800; + ;VGM_LOG("STR+WAV: header ZPb (Xbox)\n"); + return 1; + } + + /* Zapper: One Wicked Cricket! (Xbox)[2002] */ + if ( read_u32be(0x04,sf_h) == 0x00000900 && + read_u32le(0x0c,sf_h) != header_size && + read_u32le(0x24,sf_h) != 0 && + read_u32le(0x24,sf_h) == read_u32le(0xb0,sf_h) && /* sample rate repeat */ + read_u32le(0xc0,sf_h) == header_size + ) { + /* 0x08: null */ + /* 0x0c: hashname */ + strwav->num_samples = read_s32le(0x20,sf_h); + strwav->sample_rate = read_s32le(0x24,sf_h); + /* 0x28: 16 bps */ + strwav->flags = read_u32le(0x2c,sf_h); + strwav->loop_start = read_s32le(0x38,sf_h); + strwav->tracks = read_s32le(0x70,sf_h); + /* 0x78: number of chunks? */ + /* 0xb0: sample rate 2 */ + /* 0xc0: header size*/ + /* 0xd8: total frames? */ + + strwav->loop_end = strwav->num_samples; + + strwav->codec = XBOX; + strwav->interleave = strwav->tracks > 1 ? 0xD800/2 : 0xD800; + ;VGM_LOG("STR+WAV: header ZP (Xbox)\n"); + return 1; + } + + /* Zapper: One Wicked Cricket! (PC)[2002] */ if ( read_u32be(0x04,sf_h) == 0x00000900 && read_u32le(0x24,sf_h) == read_u32le(0x114,sf_h) && /* sample rate repeat */ read_u32le(0x12c,sf_h) == header_size /* ~0x130 */ @@ -514,32 +592,6 @@ static int parse_header(STREAMFILE* sf_h, STREAMFILE* sf_b, strwav_header* strwa return 1; } - /* Zapper: One Wicked Cricket! Beta (PS2)[2005] */ - if ( read_u32be(0x04,sf_h) == 0x00000900 && - read_u32le(0x2c,sf_h) == 44100 && /* sample rate */ - read_u32le(0x70,sf_h) == 0 && /* sample rate repeat? */ - header_size == 0x78 - ) { - /* 0x08: null */ - /* 0x0c: hashname */ - /* 0x28: loop start? */ - strwav->sample_rate = read_s32le(0x2c,sf_h); - /* 0x30: number of 0x800 sectors */ - strwav->flags = read_u32le(0x34,sf_h); - strwav->num_samples = read_s32le(0x5c,sf_h); - strwav->tracks = read_s32le(0x60,sf_h); - - strwav->loop_start = 0; - strwav->loop_end = 0; - - strwav->codec = PSX; - strwav->interleave = strwav->tracks > 1 ? 0x8000 : 0x8000; - //todo: tracks are stereo blocks of size 0x20000*tracks, containing 4 interleaves of 0x8000: - // | 1 2 1 2 | 3 4 3 4 | 5 6 5 6 | 1 2 1 2 | 3 4 3 4 | 5 6 5 6 | ... - ;VGM_LOG("STR+WAV: header ZPb (PS2)\n"); - return 1; - } - /* Pac-Man World 3 (GC)[2005] */ /* SpongeBob SquarePants: Creature from the Krusty Krab (GC)[2006] */ /* SpongeBob SquarePants: Creature from the Krusty Krab (Wii)[2006] */ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ubi_hx.c b/Frameworks/vgmstream/vgmstream/src/meta/ubi_hx.c index 654d85df4..e43379a33 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ubi_hx.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ubi_hx.c @@ -1,6 +1,7 @@ #include "meta.h" #include "../layout/layout.h" #include "../coding/coding.h" +#include "../util/endianness.h" typedef enum { PCM, UBI, PSX, DSP, XIMA, ATRAC3, XMA2, MP3 } ubi_hx_codec; @@ -12,14 +13,14 @@ typedef struct { int codec_id; ubi_hx_codec codec; /* unified codec */ int header_index; /* entry number within section2 */ - off_t header_offset; /* entry offset within internal .HXx */ - size_t header_size; /* entry offset within internal .HXx */ + uint32_t header_offset; /* entry offset within internal .HXx */ + uint32_t header_size; /* entry offset within internal .HXx */ char class_name[255]; size_t class_size; size_t stream_mode; - off_t stream_offset; /* data offset within external stream */ - size_t stream_size; /* data size within external stream */ + uint32_t stream_offset; /* data offset within external stream */ + uint32_t stream_size; /* data size within external stream */ uint32_t cuuid1; /* usually "Res" id1: class (1=Event, 3=Wave), id2: group id+sound id, */ uint32_t cuuid2; /* others have some complex id (not hash), id1: parent id?, id2: file id? */ @@ -47,6 +48,12 @@ VGMSTREAM* init_vgmstream_ubi_hx(STREAMFILE* sf) { /* checks */ + { + uint32_t name_size = read_u32be(0x04, sf); /* BE/LE, should always be < 0xFF */ + if (name_size == 0 || (name_size & 0x00FFFF00) != 0) + goto fail; + } + /* .hxd: Rayman M/Arena (all), PK: Out of Shadows (all) * .hxc: Rayman 3 (PC), XIII (PC) * .hx2: Rayman 3 (PS2), XIII (PS2) @@ -60,10 +67,8 @@ VGMSTREAM* init_vgmstream_ubi_hx(STREAMFILE* sf) { * then an index to those types. Some games leave a companion .bnh with text info, probably leftover from their tools. * Game seems to play files by calling linked ids: EventResData (play/stop/etc) > Random/Program/Wav ResData (1..N refs) > FileIdObj */ - /* HX CONFIG */ - hx.big_endian = guess_endianness32bit(0x00, sf); - /* HX HEADER */ + hx.big_endian = guess_endianness32bit(0x00, sf); if (!parse_hx(&hx, sf, target_subsong)) goto fail; @@ -133,8 +138,8 @@ fail: /* get referenced name from WavRes, using the index again (abridged) */ static int parse_name(ubi_hx_header* hx, STREAMFILE* sf) { - uint32_t (*read_u32)(off_t,STREAMFILE*) = hx->big_endian ? read_u32be : read_u32le; - int32_t (*read_s32)(off_t,STREAMFILE*) = hx->big_endian ? read_s32be : read_s32le; + read_u32_t read_u32 = hx->big_endian ? read_u32be : read_u32le; + read_s32_t read_s32 = hx->big_endian ? read_s32be : read_s32le; off_t index_offset, offset; int i, index_entries; char class_name[255]; @@ -228,17 +233,17 @@ fail: /* parse a single known header resource at offset */ -static int parse_header(ubi_hx_header* hx, STREAMFILE* sf, off_t offset, size_t size, int index) { - uint32_t (*read_u32)(off_t,STREAMFILE*) = hx->big_endian ? read_u32be : read_u32le; - int32_t (*read_s32)(off_t,STREAMFILE*) = hx->big_endian ? read_s32be : read_s32le; - uint16_t (*read_u16)(off_t,STREAMFILE*) = hx->big_endian ? read_u16be : read_u16le; +static int parse_header(ubi_hx_header* hx, STREAMFILE* sf, uint32_t offset, uint32_t size, int index) { + read_u32_t read_u32 = hx->big_endian ? read_u32be : read_u32le; + read_s32_t read_s32 = hx->big_endian ? read_s32be : read_s32le; + read_u16_t read_u16 = hx->big_endian ? read_u16be : read_u16le; off_t riff_offset, riff_size, chunk_offset, stream_adjust = 0, resource_size; size_t chunk_size; int cue_flag = 0; //todo cleanup/unify common readings - //;VGM_LOG("UBI HX: header o=%lx, s=%x\n\n", offset, size); + //;VGM_LOG("ubi hx: header o=%x, s=%x\n\n", offset, size); hx->header_index = index; hx->header_offset = offset; @@ -284,7 +289,7 @@ static int parse_header(ubi_hx_header* hx, STREAMFILE* sf, off_t offset, size_t } } else { - VGM_LOG("UBI HX: unknown flag-type\n"); + VGM_LOG("ubi hx: unknown flag-type\n"); goto fail; } @@ -316,7 +321,7 @@ static int parse_header(ubi_hx_header* hx, STREAMFILE* sf, off_t offset, size_t break; default: - VGM_LOG("UBI HX: %x\n", hx->stream_mode); + VGM_LOG("ubi hx: %x\n", hx->stream_mode); goto fail; } @@ -333,7 +338,7 @@ static int parse_header(ubi_hx_header* hx, STREAMFILE* sf, off_t offset, size_t case 0x05: hx->codec = XIMA; break; case 0x55: hx->codec = MP3; break; /* Largo Winch: Empire Under Threat (PC) */ default: - VGM_LOG("UBI HX: unknown codec %x\n", hx->codec_id); + VGM_LOG("ubi hx: unknown codec %x\n", hx->codec_id); goto fail; } hx->channels = read_u16(riff_offset + 0x16, sf); @@ -383,21 +388,22 @@ static int parse_header(ubi_hx_header* hx, STREAMFILE* sf, off_t offset, size_t /* 0x04: some kind of parent id shared by multiple Waves, or 0 */ offset += 0x08; - hx->stream_mode = read_8bit(offset, sf); + hx->stream_mode = read_u8(offset, sf); offset += 0x01; if ((strcmp(hx->class_name, "CXBoxStaticHWWaveFileIdObj") == 0 || strcmp(hx->class_name, "CXBoxStreamHWWaveFileIdObj") == 0) && !hx->big_endian) { /* micro header: some mix of channels + block size + sample rate + flags, unsure of which bits */ hx->codec = XIMA; - hx->channels = (uint8_t)read_8bit(offset + 0x01, sf); - switch(hx->channels) { /* upper 2 bits? */ + /* 0x00: ? */ + hx->channels = read_u8(offset + 0x01, sf); /* upper 2 bits? */ + switch(hx->channels) { case 0x48: hx->channels = 1; break; case 0x90: hx->channels = 2; break; default: goto fail; } hx->sample_rate = (read_u16(offset + 0x02, sf) & 0x7FFFu) << 1u; /* ??? */ - cue_flag = read_u8(offset + 0x03, sf) & (1<<7); + cue_flag = read_u8(offset + 0x03, sf) & (1 << 7); offset += 0x04; } else if ((strcmp(hx->class_name, "CXBoxStaticHWWaveFileIdObj") == 0 || @@ -435,6 +441,10 @@ static int parse_header(ubi_hx_header* hx, STREAMFILE* sf, off_t offset, size_t switch(hx->stream_mode) { + case 0x00: /* static (smaller internal file) [XIII (Xbox)] */ + hx->stream_offset += offset; + break; + case 0x01: /* static (smaller external file) */ case 0x03: /* stream (bigger external file) */ case 0x07: /* stream? */ @@ -446,6 +456,7 @@ static int parse_header(ubi_hx_header* hx, STREAMFILE* sf, off_t offset, size_t break; default: + VGM_LOG("ubi hx: unknown stream mode %x\n", hx->stream_mode); goto fail; } } @@ -455,22 +466,22 @@ static int parse_header(ubi_hx_header* hx, STREAMFILE* sf, off_t offset, size_t return 1; fail: - VGM_LOG("UBI HX: error parsing header at %lx\n", hx->header_offset); + vgm_logi("UBI HX: error parsing header at %x (report)\n", hx->header_offset); return 0; } /* parse a bank index and its possible audio headers (some info from Droolie's .bms) */ static int parse_hx(ubi_hx_header* hx, STREAMFILE* sf, int target_subsong) { - uint32_t (*read_u32)(off_t,STREAMFILE*) = hx->big_endian ? read_u32be : read_u32le; - int32_t (*read_s32)(off_t,STREAMFILE*) = hx->big_endian ? read_s32be : read_s32le; - off_t index_offset, offset; + read_u32_t read_u32 = hx->big_endian ? read_u32be : read_u32le; + read_s32_t read_s32 = hx->big_endian ? read_s32be : read_s32le; + uint32_t index_offset, offset; int i, index_entries; char class_name[255]; index_offset = read_u32(0x00, sf); - if (read_u32(index_offset + 0x00, sf) != 0x58444E49) /* "XDNI" (INDX in given endianness) */ + if (read_u32(index_offset + 0x00, sf) != get_id32be("XDNI")) /* (INDX in given endianness) */ goto fail; if (read_u32(index_offset + 0x04, sf) != 0x02) /* type? */ goto fail; @@ -480,11 +491,10 @@ static int parse_hx(ubi_hx_header* hx, STREAMFILE* sf, int target_subsong) { index_entries = read_s32(index_offset + 0x08, sf); offset = index_offset + 0x0c; for (i = 0; i < index_entries; i++) { - off_t header_offset; - size_t class_size, header_size; + uint32_t header_offset, class_size, header_size; int j, unknown_count, link_count, language_count; - //;VGM_LOG("UBI HX: index %i at %lx\n", i, offset); + //;VGM_LOG("ubi hx: index %i at %x\n", i, offset); /* parse index entries: offset to actual header plus some extra info also in the header */ @@ -502,7 +512,7 @@ static int parse_hx(ubi_hx_header* hx, STREAMFILE* sf, int target_subsong) { /* not seen */ unknown_count = read_s32(offset + 0x00, sf); if (unknown_count != 0) { - VGM_LOG("UBI HX: found unknown near %lx\n", offset); + VGM_LOG("ubi hx: found unknown near %x\n", offset); goto fail; } offset += 0x04; @@ -520,7 +530,7 @@ static int parse_hx(ubi_hx_header* hx, STREAMFILE* sf, int target_subsong) { /* 0x08: id1+2 */ if (read_u32(offset + 0x04, sf) != 1) { - VGM_LOG("UBI HX: wrong lang count near %lx\n", offset); + VGM_LOG("ubi hx: wrong lang count near %x\n", offset); goto fail; /* WavRes doesn't have this field */ } offset += 0x10; @@ -557,12 +567,12 @@ static int parse_hx(ubi_hx_header* hx, STREAMFILE* sf, int target_subsong) { ; } else { - VGM_LOG("UBI HX: unknown type: %s\n", class_name); + vgm_logi("UBI HX: unknown type: %s (report)\n", class_name); goto fail; } if (link_count != 0) { - VGM_LOG("UBI HX: found links in wav object\n"); + vgm_logi("UBI HX: found links in wav object (report)\n"); goto fail; } @@ -596,7 +606,7 @@ static STREAMFILE* open_hx_streamfile(ubi_hx_header* hx, STREAMFILE* sf) { sb = open_streamfile_by_filename(sf, hx->resource_name); if (sb == NULL) { - VGM_LOG("UBI HX: external stream '%s' not found\n", hx->resource_name); + vgm_logi("UBI HX: external file '%s' not found (put together)\n", hx->resource_name); goto fail; } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/wwise.c b/Frameworks/vgmstream/vgmstream/src/meta/wwise.c index ee8c1ec33..b906d3e66 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/wwise.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/wwise.c @@ -1,6 +1,8 @@ #include "meta.h" #include "../util.h" #include "../coding/coding.h" +#include "../util/chunks.h" +#include "../util/endianness.h" /* Wwise uses a custom RIFF/RIFX header, non-standard enough that it's parsed it here. @@ -14,6 +16,7 @@ typedef struct { int big_endian; size_t file_size; int truncated; + int is_wem; /* chunks references */ off_t fmt_offset; @@ -55,22 +58,28 @@ static int parse_wwise(STREAMFILE* sf, wwise_header* ww); static int is_dsp_full_interleave(STREAMFILE* sf, wwise_header* ww, off_t coef_offset); -/* Wwise - Audiokinetic Wwise (Wave Works Interactive Sound Engine) middleware */ + +/* Wwise - Audiokinetic Wwise (WaveWorks Interactive Sound Engine) middleware */ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) { VGMSTREAM* vgmstream = NULL; wwise_header ww = {0}; off_t start_offset; - uint32_t (*read_u32)(off_t,STREAMFILE*) = NULL; - int32_t (*read_s32)(off_t,STREAMFILE*) = NULL; - uint16_t (*read_u16)(off_t,STREAMFILE*) = NULL; + read_u32_t read_u32 = NULL; + read_s32_t read_s32 = NULL; + read_u16_t read_u16 = NULL; /* checks */ - /* .wem: newer "Wwise Encoded Media" used after the 2011.2 SDK (~july 2011) + if (!is_id32be(0x00,sf, "RIFF") && /* LE */ + !is_id32be(0x00,sf, "RIFX")) /* BE */ + goto fail; + + /* note that Wwise allows those extensions only, so custom engine exts shouldn't be added + * .wem: newer "Wwise Encoded Media" used after the 2011.2 SDK (~july 2011) * .wav: older PCM/ADPCM files [Spider-Man: Web of Shadows (PC), Punch Out!! (Wii)] * .xma: older XMA files [Too Human (X360), Tron Evolution (X360)] * .ogg: older Vorbis files [The King of Fighters XII (X360)] - * .bnk: Wwise banks for memory .wem detection */ + * .bnk: Wwise banks for memory .wem detection (hack) */ if (!check_extensions(sf,"wem,wav,lwav,ogg,logg,xma,bnk")) goto fail; @@ -92,6 +101,7 @@ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) { vgmstream->loop_start_sample = ww.loop_start_sample; vgmstream->loop_end_sample = ww.loop_end_sample; vgmstream->channel_layout = ww.channel_layout; + vgmstream->stream_size = ww.data_size; switch(ww.codec) { case PCM: /* common */ @@ -234,7 +244,6 @@ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) { else { /* newer Wwise (>2012) */ off_t extra_offset = ww.fmt_offset + 0x18; /* after flag + channels */ - int is_wem = check_extensions(sf,"wem,bnk"); /* use extension as a guide for faster vorbis inits */ switch(ww.extra_size) { case 0x30: @@ -246,7 +255,7 @@ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) { /* setup not detectable by header, so we'll try both; libvorbis should reject wrong codebooks * - standard: early (<2012), ex. The King of Fighters XIII (X360)-2011/11, .ogg (cbs are from aoTuV, too) * - aoTuV603: later (>2012), ex. Sonic & All-Stars Racing Transformed (PC)-2012/11, .wem */ - cfg.setup_type = is_wem ? WWV_AOTUV603_CODEBOOKS : WWV_EXTERNAL_CODEBOOKS; /* aoTuV came along .wem */ + cfg.setup_type = ww.is_wem ? WWV_AOTUV603_CODEBOOKS : WWV_EXTERNAL_CODEBOOKS; /* aoTuV came along .wem */ break; default: @@ -278,7 +287,7 @@ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) { vgmstream->codec_data = init_vorbis_custom(sf, start_offset + setup_offset, VORBIS_WWISE, &cfg); if (!vgmstream->codec_data) { /* codebooks failed: try again with the other type */ - cfg.setup_type = is_wem ? WWV_EXTERNAL_CODEBOOKS : WWV_AOTUV603_CODEBOOKS; + cfg.setup_type = ww.is_wem ? WWV_EXTERNAL_CODEBOOKS : WWV_AOTUV603_CODEBOOKS; vgmstream->codec_data = init_vorbis_custom(sf, start_offset + setup_offset, VORBIS_WWISE, &cfg); if (!vgmstream->codec_data) goto fail; } @@ -690,18 +699,12 @@ static int is_dsp_full_interleave(STREAMFILE* sf, wwise_header* ww, off_t coef_o static int parse_wwise(STREAMFILE* sf, wwise_header* ww) { - uint32_t (*read_u32)(off_t,STREAMFILE*) = NULL; - uint16_t (*read_u16)(off_t,STREAMFILE*) = NULL; + read_u32_t read_u32; + read_u16_t read_u16; - if (read_u32be(0x00,sf) != 0x52494646 && /* "RIFF" (LE) */ - read_u32be(0x00,sf) != 0x52494658) /* "RIFX" (BE) */ - goto fail; - if (read_u32be(0x08,sf) != 0x57415645 && /* "WAVE" */ - read_u32be(0x08,sf) != 0x58574D41) /* "XWMA" */ - goto fail; - - ww->big_endian = read_u32be(0x00,sf) == 0x52494658; /* RIFX */ - if (ww->big_endian) { /* Wwise honors machine's endianness (PC=RIFF, X360=RIFX --unlike XMA) */ + /* Wwise honors machine's endianness (PC=RIFF, X360=RIFX --unlike XMA) */ + ww->big_endian = is_id32be(0x00,sf, "RIFX"); /* RIFF size not useful to detect, see below */ + if (ww->big_endian) { read_u32 = read_u32be; read_u16 = read_u16be; } else { @@ -727,50 +730,56 @@ static int parse_wwise(STREAMFILE* sf, wwise_header* ww) { } #endif + if (!is_id32be(0x08,sf, "WAVE") && + !is_id32be(0x08,sf, "XWMA")) + goto fail; + + /* parse chunks (reads once linearly) */ { - off_t offset = 0x0c; - while (offset < ww->file_size) { - uint32_t type = read_u32be(offset + 0x00,sf); - uint32_t size = read_u32 (offset + 0x04,sf); - offset += 0x08; + chunk_t rc = {0}; - switch(type) { + /* chunks are even-aligned and don't need to add padding byte, unlike real RIFFs */ + rc.be_size = ww->big_endian; + rc.current = 0x0c; + while (next_chunk(&rc, sf)) { + + switch(rc.type) { case 0x666d7420: /* "fmt " */ - ww->fmt_offset = offset; - ww->fmt_size = size; + ww->fmt_offset = rc.offset; + ww->fmt_size = rc.size; break; case 0x584D4132: /* "XMA2" */ - ww->xma2_offset = offset; - ww->xma2_size = size; + ww->xma2_offset = rc.offset; + ww->xma2_size = rc.size; break; case 0x64617461: /* "data" */ - ww->data_offset = offset; - ww->data_size = size; + ww->data_offset = rc.offset; + ww->data_size = rc.size; break; case 0x766F7262: /* "vorb" */ - ww->vorb_offset = offset; - ww->vorb_size = size; + ww->vorb_offset = rc.offset; + ww->vorb_size = rc.size; break; case 0x57696948: /* "WiiH" */ - ww->wiih_offset = offset; - ww->wiih_size = size; + ww->wiih_offset = rc.offset; + ww->wiih_size = rc.size; break; case 0x7365656B: /* "seek" */ - ww->seek_offset = offset; - ww->seek_size = size; + ww->seek_offset = rc.offset; + ww->seek_size = rc.size; break; case 0x736D706C: /* "smpl" */ - ww->smpl_offset = offset; - ww->smpl_size = size; + ww->smpl_offset = rc.offset; + ww->smpl_size = rc.size; break; case 0x6D657461: /* "meta" */ - ww->meta_offset = offset; - ww->meta_size = size; + ww->meta_offset = rc.offset; + ww->meta_size = rc.size; break; case 0x66616374: /* "fact" */ - /* Wwise shouldn't use fact, but if somehow some file does uncomment the following: */ + /* Wwise never uses fact, but if somehow some file does uncomment the following: */ //if (size == 0x10 && read_u32be(offset + 0x04, sf) == 0x4C794E20) /* "LyN " */ // goto fail; /* ignore LyN RIFF */ goto fail; @@ -783,12 +792,11 @@ static int parse_wwise(STREAMFILE* sf, wwise_header* ww) { default: break; } - - /* chunks are even-aligned and don't need to add padding byte, unlike real RIFFs */ - offset += size; } } + /* use extension as a guide for certain cases */ + ww->is_wem = check_extensions(sf,"wem,bnk"); /* parse format (roughly spec-compliant but some massaging is needed) */ if (ww->xma2_offset) { @@ -806,7 +814,7 @@ static int parse_wwise(STREAMFILE* sf, wwise_header* ww) { ww->channels = read_u16(ww->fmt_offset + 0x02,sf); ww->sample_rate = read_u32(ww->fmt_offset + 0x04,sf); ww->avg_bitrate = read_u32(ww->fmt_offset + 0x08,sf); - ww->block_size = read_u16(ww->fmt_offset + 0x0c,sf); + ww->block_size = read_u16(ww->fmt_offset + 0x0c,sf); ww->bits_per_sample = read_u16(ww->fmt_offset + 0x0e,sf); if (ww->fmt_size > 0x10 && ww->format != 0x0165 && ww->format != 0x0166) /* ignore XMAWAVEFORMAT */ ww->extra_size = read_u16(ww->fmt_offset + 0x10,sf); @@ -864,7 +872,9 @@ static int parse_wwise(STREAMFILE* sf, wwise_header* ww) { case 0x3041: ww->codec = OPUSWW; break; /* "OPUS_WEM", added on Wwise 2019.2.3, replaces OPUS */ case 0x8311: ww->codec = PTADPCM; break; /* added on Wwise 2019.1, replaces IMA */ default: - vgm_logi("WWISE: unknown codec 0x%04x (report)\n", ww->format); + /* some .wav may end up here, only report in .wem cases (newer codecs) */ + if (ww->is_wem) + vgm_logi("WWISE: unknown codec 0x%04x (report)\n", ww->format); goto fail; } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/xnb.c b/Frameworks/vgmstream/vgmstream/src/meta/xnb.c index 25d42c2a0..0b8152e1d 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/xnb.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/xnb.c @@ -17,10 +17,10 @@ VGMSTREAM* init_vgmstream_xnb(STREAMFILE* sf) { /* checks */ - if (!check_extensions(sf,"xnb")) - goto fail; if ((read_u32be(0x00, sf) & 0xFFFFFF00) != get_id32be("XNB\0")) goto fail; + if (!check_extensions(sf,"xnb")) + goto fail; /* XNA Studio platforms: 'w' = Windows, 'm' = Windows Phone 7, 'x' = X360 * MonoGame extensions: 'i' = iOS, 'a' = Android, 'X' = MacOSX, 'P' = PS4, 'S' = Switch, etc */ @@ -184,10 +184,9 @@ VGMSTREAM* init_vgmstream_xnb(STREAMFILE* sf) { if (!temp_sf) goto fail; if (is_ogg) { -#ifdef VGM_USE_VORBIS vgmstream = init_vgmstream_ogg_vorbis(temp_sf); -#endif - } else { + } + else { vgmstream = init_vgmstream_riff(temp_sf); } close_streamfile(temp_sf); diff --git a/Frameworks/vgmstream/vgmstream/src/streamfile.c b/Frameworks/vgmstream/vgmstream/src/streamfile.c index b4dc34ed7..da43bcef0 100644 --- a/Frameworks/vgmstream/vgmstream/src/streamfile.c +++ b/Frameworks/vgmstream/vgmstream/src/streamfile.c @@ -16,11 +16,11 @@ * - Clang: seems only defined on Linux/GNU environments, somehow emscripten is out * (unsure about Clang Win since apparently they define _MSC_VER) * - Android: API +24 if not using __USE_FILE_OFFSET64 - * Not sure if fopen64 is needed in some cases. May be worth adding some compiler flag to enable 64 versions manually. + * Not sure if fopen64 is needed in some cases. */ -/* MSVC fixes (though mingw uses MSVCRT but not MSC_VER, maybe use AND?) */ -#if defined(__MSVCRT__) || defined(_MSC_VER) +#if defined(_MSC_VER) //&& defined(__MSVCRT__) + /* MSVC fixes (MinG64 seems to set MSVCRT too, but we want it below) */ #include #define fopen_v fopen @@ -43,14 +43,22 @@ // #define off_t/off64_t __int64 //#endif +#elif defined(VGMSTREAM_USE_IO64) || defined(__MINGW32__) || defined(__MINGW64__) + /* force, or known to work */ + #define fopen_v fopen + #define fseek_v fseeko64 //fseeko + #define ftell_v ftello64 //ftello + #elif defined(XBMC) || defined(__EMSCRIPTEN__) || defined (__ANDROID__) || defined(__APPLE__) + /* may depend on version */ #define fopen_v fopen #define fseek_v fseek #define ftell_v ftell #else + /* other Linux systems may already use off64_t in fseeko/ftello? */ #define fopen_v fopen - #define fseek_v fseeko64 //fseeko - #define ftell_v ftello64 //ftello + #define fseek_v fseeko + #define ftell_v ftello #endif @@ -952,22 +960,12 @@ STREAMFILE* open_streamfile(STREAMFILE* sf, const char* pathname) { STREAMFILE* open_streamfile_by_ext(STREAMFILE* sf, const char* ext) { char filename[PATH_LIMIT]; - int filename_len, fileext_len; - sf->get_name(sf, filename, sizeof(filename)); + get_streamfile_name(sf, filename, sizeof(filename)); - filename_len = strlen(filename); - fileext_len = strlen(filename_extension(filename)); + swap_extension(filename, sizeof(filename), ext); - if (fileext_len == 0) {/* extensionless */ - strcat(filename,"."); - strcat(filename,ext); - } - else { - strcpy(filename + filename_len - fileext_len, ext); - } - - return sf->open(sf, filename, STREAMFILE_DEFAULT_BUFFER_SIZE); + return open_streamfile(sf, filename); } STREAMFILE* open_streamfile_by_filename(STREAMFILE* sf, const char* filename) { @@ -977,7 +975,7 @@ STREAMFILE* open_streamfile_by_filename(STREAMFILE* sf, const char* filename) { if (!sf || !filename || !filename[0]) return NULL; - sf->get_name(sf, fullname, sizeof(fullname)); + get_streamfile_name(sf, fullname, sizeof(fullname)); //todo normalize separators in a better way, safeops, improve copying @@ -1026,7 +1024,7 @@ STREAMFILE* open_streamfile_by_filename(STREAMFILE* sf, const char* filename) { strcpy(fullname, filename); } - return sf->open(sf, fullname, STREAMFILE_DEFAULT_BUFFER_SIZE); + return open_streamfile(sf, fullname); } STREAMFILE* reopen_streamfile(STREAMFILE* sf, size_t buffer_size) { @@ -1036,7 +1034,7 @@ STREAMFILE* reopen_streamfile(STREAMFILE* sf, size_t buffer_size) { if (buffer_size == 0) buffer_size = STREAMFILE_DEFAULT_BUFFER_SIZE; - sf->get_name(sf, pathname,sizeof(pathname)); + get_streamfile_name(sf, pathname, sizeof(pathname)); return sf->open(sf, pathname, buffer_size); } @@ -1262,6 +1260,11 @@ STREAMFILE* read_filemap_file_pos(STREAMFILE* sf, int file_num, int* p_pos) { /* get key/val (ignores lead/trailing spaces, stops at comment/separator) */ ok = sscanf(line, " %[^\t#:] : %[^\t#\r\n] ", key, val); if (ok != 2) { /* ignore line if no key=val (comment or garbage) */ + /* better way? */ + if (strcmp(line, "#@reset-pos") == 0) { + file_pos = 0; + VGM_LOG("pos =%i\n", file_pos); + } continue; } diff --git a/Frameworks/vgmstream/vgmstream/src/util.c b/Frameworks/vgmstream/vgmstream/src/util.c index 3c7ccc3e6..858f6a4a8 100644 --- a/Frameworks/vgmstream/vgmstream/src/util.c +++ b/Frameworks/vgmstream/vgmstream/src/util.c @@ -2,34 +2,40 @@ #include "util.h" #include "streamtypes.h" -const char * filename_extension(const char * pathname) { - const char * filename; - const char * extension; +const char* filename_extension(const char* pathname) { + const char* extension; /* favor strrchr (optimized/aligned) rather than homemade loops */ + extension = strrchr(pathname,'.'); - /* find possible separator first to avoid misdetecting folders with dots + extensionless files - * (allow both slashes as plugin could pass normalized '/') */ - filename = strrchr(pathname, '/'); - if (filename != NULL) - filename++; /* skip separator */ - else { - filename = strrchr(pathname, '\\'); - if (filename != NULL) - filename++; /* skip separator */ - else - filename = pathname; /* pathname has no separators (single filename) */ + if (extension != NULL) { + /* probably has extension */ + extension++; /* skip dot */ + + /* find possible separators to avoid misdetecting folders with dots + extensionless files + * (after the above to reduce search space, allows both slashes in case of non-normalized names) */ + if (strchr(extension, '/') == NULL && strchr(extension, '\\') == NULL) + return extension; /* no slashes = really has extension */ } - extension = strrchr(filename,'.'); - if (extension != NULL) - extension++; /* skip dot */ - else - extension = filename + strlen(filename); /* point to null (empty "" string for extensionless files) */ - - return extension; + /* extensionless: point to null after current name + * (could return NULL but prev code expects with to return an actual c-string) */ + return pathname + strlen(pathname); } +void swap_extension(char* pathname, int pathname_len, const char* swap) { + char* extension = (char*)filename_extension(pathname); + //todo safeops + if (extension[0] == '\0') { + strcat(pathname, "."); + strcat(pathname, swap); + } + else { + strcpy(extension, swap); + } +} + + /* unused */ /* void interleave_channel(sample_t * outbuffer, sample_t * inbuffer, int32_t sample_count, int channel_count, int channel_number) { diff --git a/Frameworks/vgmstream/vgmstream/src/util.h b/Frameworks/vgmstream/vgmstream/src/util.h index 0e4aae73f..06fffed1c 100644 --- a/Frameworks/vgmstream/vgmstream/src/util.h +++ b/Frameworks/vgmstream/vgmstream/src/util.h @@ -175,7 +175,10 @@ int round10(int val); /* return a file's extension (a pointer to the first character of the * extension in the original filename or the ending null byte if no extension */ -const char * filename_extension(const char * filename); +const char* filename_extension(const char* pathname); + +/* change pathname's extension to another (or add it if extensionless) */ +void swap_extension(char* pathname, /*size_t*/ int pathname_len, const char* swap); /* swap samples in machine endianness to little endian (useful to write .wav) */ void swap_samples_le(sample_t *buf, int count); diff --git a/Frameworks/vgmstream/vgmstream/src/util/chunks.c b/Frameworks/vgmstream/vgmstream/src/util/chunks.c index 214865864..0898dfd1d 100644 --- a/Frameworks/vgmstream/vgmstream/src/util/chunks.c +++ b/Frameworks/vgmstream/vgmstream/src/util/chunks.c @@ -26,8 +26,8 @@ int next_chunk(chunk_t* chunk, STREAMFILE* sf) { if (chunk->type == 0xFFFFFFFF || chunk->size == 0xFFFFFFFF) return 0; - /* empty chunk with 0 size, seen in some formats (XVAG uses it as end marker, Wwise doesn't) */ - if (chunk->type == 0 || chunk->size == 0) + /* empty chunk with 0 size is ok, seen in some formats (XVAG uses it as end marker, Wwise in JUNK) */ + if (chunk->type == 0 /*|| chunk->size == 0*/) return 0; /* more chunks remain */ diff --git a/Frameworks/vgmstream/vgmstream/src/util/chunks.h b/Frameworks/vgmstream/vgmstream/src/util/chunks.h index 0df77cc53..3d5ffe082 100644 --- a/Frameworks/vgmstream/vgmstream/src/util/chunks.h +++ b/Frameworks/vgmstream/vgmstream/src/util/chunks.h @@ -13,6 +13,7 @@ typedef struct { int le_type; /* read type as LE instead of more common BE */ int be_size; /* read type as BE instead of more common LE */ int full_size; /* chunk size includes type+size */ + int alignment; /* chunks with odd size need to be aligned to even, per RIFF spec */ } chunk_t; int next_chunk(chunk_t* chunk, STREAMFILE* sf); diff --git a/Frameworks/vgmstream/vgmstream/src/util/endianness.h b/Frameworks/vgmstream/vgmstream/src/util/endianness.h new file mode 100644 index 000000000..ce5abe9a5 --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/util/endianness.h @@ -0,0 +1,10 @@ +#ifndef _UTIL_ENDIAN_H +#define _UTIL_ENDIAN_H + +#include "../streamfile.h" + +typedef uint32_t (*read_u32_t)(off_t, STREAMFILE*); +typedef int32_t (*read_s32_t)(off_t, STREAMFILE*); +typedef uint16_t (*read_u16_t)(off_t, STREAMFILE*); + +#endif diff --git a/Frameworks/vgmstream/vgmstream/src/vgmstream.c b/Frameworks/vgmstream/vgmstream/src/vgmstream.c index fbebc29cb..f05370cb1 100644 --- a/Frameworks/vgmstream/vgmstream/src/vgmstream.c +++ b/Frameworks/vgmstream/vgmstream/src/vgmstream.c @@ -22,8 +22,6 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = { init_vgmstream_adx, init_vgmstream_brstm, init_vgmstream_bfwav, - init_vgmstream_bfstm, - init_vgmstream_mca, init_vgmstream_nds_strm, init_vgmstream_agsc, init_vgmstream_ngc_adpdtk, @@ -61,17 +59,9 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = { init_vgmstream_caf, init_vgmstream_vpk, init_vgmstream_genh, -#ifdef VGM_USE_VORBIS init_vgmstream_ogg_vorbis, -#endif init_vgmstream_sli_ogg, init_vgmstream_sfl_ogg, -#if 0 - init_vgmstream_mp4_aac, -#endif -#if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC) - init_vgmstream_akb_mp4, -#endif init_vgmstream_sadb, init_vgmstream_ps2_bmdx, init_vgmstream_wsi, @@ -294,6 +284,14 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = { init_vgmstream_idsp_namco, init_vgmstream_kt_g1l, init_vgmstream_kt_wiibgm, + init_vgmstream_bfstm, + init_vgmstream_mca, +#if 0 + init_vgmstream_mp4_aac, +#endif +#if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC) + init_vgmstream_akb_mp4, +#endif init_vgmstream_ktss, init_vgmstream_hca, init_vgmstream_svag_snk, diff --git a/Plugins/vgmstream/vgmstream/VGMDecoder.m b/Plugins/vgmstream/vgmstream/VGMDecoder.m index aac438722..fd4c9f4b0 100644 --- a/Plugins/vgmstream/vgmstream/VGMDecoder.m +++ b/Plugins/vgmstream/vgmstream/VGMDecoder.m @@ -11,17 +11,21 @@ #import "PlaylistController.h" +#include + static NSString* get_description_tag(const char* description, const char *tag, char delimiter) { // extract a "tag" from the description string + if (!delimiter) delimiter = '\n'; const char* pos = strstr(description, tag); const char* eos = NULL; if (pos != NULL) { pos += strlen(tag); eos = strchr(pos, delimiter); if (eos == NULL) eos = pos + strlen(pos); - NSMutableData* data = [NSData dataWithBytes:pos length:(eos - pos + 1)]; - ((char *)[data mutableBytes])[eos - pos] = '\0'; - return [NSString stringWithUTF8String:[data bytes]]; + char temp[eos - pos + 1]; + memcpy(temp, pos, eos - pos); + temp[eos - pos] = '\0'; + return [NSString stringWithUTF8String:temp]; } return nil; }