diff --git a/Frameworks/vgmstream/vgmstream/src/coding/xa_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/xa_decoder.c index 96b6568db..7931247c7 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/xa_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/xa_decoder.c @@ -1,70 +1,97 @@ #include "coding.h" #include "../util.h" -const int SH = 4; -const int SHC = 10; +// todo this is based on Kazzuya's old code; different emus (PCSX, Mame, Mednafen, etc) do +// XA coefs int math in different ways (see comments below), so may not be 100% accurate. +// May be implemented like the SNES/SPC700 BRR (per-filter code?). -double K0[4] = { 0.0, 0.9375, 1.796875, 1.53125}; -double K1[4] = { 0.0, 0.0, -0.8125,-0.859375}; - -static int IK0(int fid) -{ return ((int)((-K0[fid]) * (1 << SHC))); } - -static int IK1(int fid) -{ return ((int)((-K1[fid]) * (1 << SHC))); } - -static int CLAMP(int value, int Minim, int Maxim) -{ - if (value < Minim) value = Minim; - if (value > Maxim) value = Maxim; - return value; -} +/* XA ADPCM gain values */ +static const double K0[4] = { 0.0, 0.9375, 1.796875, 1.53125 }; +static const double K1[4] = { 0.0, 0.0, -0.8125,-0.859375}; +static int IK0(int fid) { return ((int)((-K0[fid]) * (1 << 10))); } /* K0/1 floats to int, K*2^10 = K*1024 */ +static int IK1(int fid) { return ((int)((-K1[fid]) * (1 << 10))); } +/* Sony XA ADPCM, defined for CD-DA/CD-i in the "Red Book" (private) or "Green Book" (public) specs. + * The algorithm basically is BRR (Bit Rate Reduction) from the SNES SPC700, while the data layout is new. + * + * Decoding is defined in diagrams, roughly as: + * pcm = clamp( signed_nibble * 2^(12-range) + K0[index]*hist1 + K1[index]*hist2 ) + * - Range (12-range=shift) and filter index are renewed every ~28 samples. + * - nibble is expanded to a signed 16b sample, reimplemented as: + * short sample = ((nibble << 12) & 0xf000) >> shift + * or: int sample = ((nibble << 28) & 0xf0000000) >> (shift + N) + * - K0/K1 are float coefs are typically redefined with int math in various ways, with non-equivalent rounding: + * (sample + K0*2^N*hist1 + K1*2^N*hist1 + [(2^N)/2]) / 2^N + * (sample + K0*2^N*hist1 + K1*2^N*hist1 + [(2^N)/2]) >> N + * sample + (K0<>N + * sample + (K0*2^N*hist1)>>N + (K1*2^N*hist1)>>N + * etc + * (rounding differences should be inaudible, so public implementations may be approximations) + * + * Various XA descendants (PS-ADPCM, EA-XA, NGC DTK, FADPCM, etc) do filters/rounding slightly + * differently, using one of the above methods. + * int coef tables commonly use N = 6 or 8, so K0 0.9375*64 = 60 or 0.9375*256 = 240 + * PS1 XA is apparently upsampled and interpolated to 44100, vgmstream doesn't simulate this. + * + * Info (Green Book): https://www.lscdweb.com/data/downloadables/2/8/cdi_may94_r2.pdf + */ void decode_xa(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) { - + static int head_table[8] = {0,2,8,10}; VGMSTREAMCHANNEL * stream = &(vgmstream->ch[channel]); - int predict_nr, shift_factor, sample; - int32_t hist1=stream->adpcm_history1_32; - int32_t hist2=stream->adpcm_history2_32; - int HeadTable[8]={0,2,8,10}; + off_t sp_offset; + int i; + int frames_in, sample_count = 0; + int32_t coef1, coef2, coef_index, shift_factor; + int32_t hist1 = stream->adpcm_history1_32; + int32_t hist2 = stream->adpcm_history2_32; - short scale; - int i; - int32_t sample_count; + /* external interleave (fixed size), mono/stereo */ + frames_in = first_sample / (28*2 / channelspacing); + first_sample = first_sample % 28; - int framesin = first_sample / (56 / channelspacing); + /* hack for mono/stereo handling */ + vgmstream->xa_get_high_nibble = !vgmstream->xa_get_high_nibble; + if (first_sample && channelspacing==1) + vgmstream->xa_get_high_nibble = !vgmstream->xa_get_high_nibble; + + /* parse current sound unit (subframe) sound parameters */ + sp_offset = stream->offset+head_table[frames_in]+vgmstream->xa_get_high_nibble; + coef_index = (read_8bit(sp_offset,stream->streamfile) >> 4) & 0xf; + shift_factor = (read_8bit(sp_offset,stream->streamfile) ) & 0xf; + + VGM_ASSERT(coef_index > 4 || shift_factor > 12, "XA: incorrect coefs/shift at %lx\n", sp_offset); + if (coef_index > 4) + coef_index = 0; /* only 4 filters are used, rest is apparently 0 */ + if (shift_factor > 12) + shift_factor = 9; /* supposedly, from Nocash PSX docs */ + + coef1 = IK0(coef_index); + coef2 = IK1(coef_index); - first_sample = first_sample % 28; - - vgmstream->xa_get_high_nibble=!vgmstream->xa_get_high_nibble; + /* decode nibbles */ + for (i = first_sample; i < first_sample + samples_to_do; i++) { + int32_t new_sample; + uint8_t nibbles = (uint8_t)read_8bit(stream->offset+0x10+frames_in+(i*0x04),stream->streamfile); - if((first_sample) && (channelspacing==1)) - vgmstream->xa_get_high_nibble=!vgmstream->xa_get_high_nibble; + new_sample = vgmstream->xa_get_high_nibble ? + (nibbles >> 4) & 0x0f : + (nibbles ) & 0x0f; + new_sample = (int16_t)((new_sample << 12) & 0xf000) >> shift_factor; /* 16b sign extend + scale */ + new_sample = new_sample << 4; + new_sample = new_sample - ((coef1*hist1 + coef2*hist2) >> 10); - predict_nr = read_8bit(stream->offset+HeadTable[framesin]+vgmstream->xa_get_high_nibble,stream->streamfile) >> 4; - shift_factor = read_8bit(stream->offset+HeadTable[framesin]+vgmstream->xa_get_high_nibble,stream->streamfile) & 0xf; + hist2 = hist1; + hist1 = new_sample; /* must go before clamp, somehow */ + new_sample = new_sample >> 4; + new_sample = clamp16(new_sample); - for (i=first_sample,sample_count=0; ioffset+16+framesin+(i*4),stream->streamfile); + outbuf[sample_count] = new_sample; + sample_count += channelspacing; + } - scale = ((vgmstream->xa_get_high_nibble ? - sample_byte >> 4 : - sample_byte & 0x0f)<<12); - - sample = (short)(scale & 0xf000) >> shift_factor; - sample <<= SH; - sample -= (IK0(predict_nr) * hist1 + (IK1(predict_nr) * hist2)) >> SHC; - - hist2=hist1; - hist1=sample; - - sample = CLAMP(sample, -32768 << SH, 32767 << SH); - outbuf[sample_count] = (short)(sample >> SH); - } - - stream->adpcm_history1_32=hist1; - stream->adpcm_history2_32=hist2; + stream->adpcm_history1_32 = hist1; + stream->adpcm_history2_32 = hist2; } size_t xa_bytes_to_samples(size_t bytes, int channels, int is_blocked) { diff --git a/Frameworks/vgmstream/vgmstream/src/formats.c b/Frameworks/vgmstream/vgmstream/src/formats.c index 019be68ea..c503a4318 100644 --- a/Frameworks/vgmstream/vgmstream/src/formats.c +++ b/Frameworks/vgmstream/vgmstream/src/formats.c @@ -1,13 +1,16 @@ #include "vgmstream.h" -//#define VGM_REGISTER_TYPE(extension) ... -//#define VGM_REGISTER_TYPE_COMMON(extension) ... /* for common extensions like aiff */ +/* defines the list of accepted extensions. vgmstream doesn't use it internally so it's here + * to inform plugins that need it. Common extensions are commented out to avoid stealing them. */ -/* some extensions could be #ifdef but no really needed */ +/* some extensions require external libraries and could be #ifdef, no really needed */ /* some formats marked as "not parsed" mean they'll go through FFmpeg, the header/extension is not parsed */ + static const char* extension_list[] = { + //"", /* vgmstream can plays extensionless files too, but plugins must accept them manually */ + "04sw", "2dx9", "2pfs", @@ -38,6 +41,7 @@ static const char* extension_list[] = { "al2", "amts", //fake extension/header id for .stm (to be removed) "ao", //txth/reserved [Cloudphobia (PC)] + "apc", //txth/reserved [MegaRace 3 (PC)] "as4", "asd", "asf", @@ -343,6 +347,7 @@ static const char* extension_list[] = { "stx", "svag", "svs", + "svg", //txth/reserved [Hunter: The Reckoning - Wayward (PS2)] "swag", "swav", "swd", @@ -367,6 +372,7 @@ static const char* extension_list[] = { "v0", //"v1", //dual channel with v0 "vag", + "vai", //txth/reserved [Ratatouille (GC)] "vas", "vawx", "vb", @@ -435,7 +441,7 @@ static const char* extension_list[] = { "zsd", "zwdsp", - "vgmstream" + "vgmstream" /* fake extension, catch-all for FFmpeg/txth/etc */ //, NULL //end mark }; @@ -829,7 +835,7 @@ static const meta_info meta_info_list[] = { {meta_PS2_MCG, "Gunvari MCG Header"}, {meta_ZSD, "ZSD Header"}, {meta_RedSpark, "RedSpark Header"}, - {meta_PC_IVAUD, "assumed GTA IV Audio file by .ivaud extension"}, + {meta_IVAUD, "Rockstar .ivaud header"}, {meta_DSP_WII_WSD, ".WSD header"}, {meta_WII_NDP, "Icon Games NDP header"}, {meta_PS2_SPS, "Ape Escape 2 SPS Header"}, @@ -907,7 +913,7 @@ static const meta_info meta_info_list[] = { {meta_X360_TRA, "Terminal Reality .TRA raw header"}, {meta_PS2_VGS, "Princess Soft VGS header"}, {meta_PS2_IAB, "Runtime .IAB header"}, - {meta_PS2_STRLR, "STR L/R header"}, + {meta_PS2_STRLR, "The Bouncer STR header"}, {meta_LSF_N1NJ4N, ".lsf !n1nj4n header"}, {meta_VAWX, "feelplus VAWX header"}, {meta_PC_SNDS, "assumed Heavy Iron IMA by .snds extension"}, @@ -1023,6 +1029,7 @@ static const meta_info meta_info_list[] = { {meta_OGG_GWM, "Ogg Vorbis (GWM header)"}, {meta_DSP_SADF, "Procyon Studio SADF header"}, {meta_H4M, "Hudson HVQM4 header"}, + {meta_OGG_MUS, "Ogg Vorbis (MUS header)"}, #ifdef VGM_USE_FFMPEG {meta_FFmpeg, "FFmpeg supported file format"}, diff --git a/Frameworks/vgmstream/vgmstream/src/layout/blocked_ea_schl.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_ea_schl.c index b4a37ab14..f4fbee6e6 100644 --- a/Frameworks/vgmstream/vgmstream/src/layout/blocked_ea_schl.c +++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked_ea_schl.c @@ -1,187 +1,192 @@ -#include "layout.h" -#include "../coding/coding.h" -#include "../vgmstream.h" - -/* parse EA style blocks, id+size+samples+data */ -void block_update_ea_schl(off_t block_offset, VGMSTREAM * vgmstream) { - STREAMFILE* streamFile = vgmstream->ch[0].streamfile; - int i; - int new_schl = 0; - size_t block_size, block_samples; - int32_t (*read_32bit)(off_t,STREAMFILE*) = vgmstream->codec_endian ? read_32bitBE : read_32bitLE; - - - /* EOF reads: signal we have nothing and let the layout fail */ - if (block_offset >= get_streamfile_size(streamFile)) { - vgmstream->current_block_offset = block_offset; - vgmstream->next_block_offset = block_offset; - vgmstream->current_block_samples = -1; - return; - } - - /* read a single block */ - { - uint32_t block_id = read_32bitBE(block_offset+0x00,streamFile); - - block_size = read_32bitLE(block_offset+0x04,streamFile); - if (block_size > 0x00F00000) /* size is always LE, except in early SAT/MAC */ - block_size = read_32bitBE(block_offset+0x04,streamFile); - - switch(block_id) { - case 0x5343446C: /* "SCDl" */ - case 0x5344454E: /* "SDEN" */ - case 0x53444652: /* "SDFR" */ - case 0x53444745: /* "SDGE" */ - case 0x53444954: /* "SDIT" */ - case 0x53445350: /* "SDSP" */ - case 0x53445255: /* "SDRU" */ - case 0x53444A41: /* "SDJA" */ - /* audio chunk */ - if (vgmstream->coding_type == coding_PSX) - block_samples = ps_bytes_to_samples(block_size-0x10, vgmstream->channels); - else - block_samples = read_32bit(block_offset+0x08,streamFile); - break; - default: - /* ignore other chunks (audio "SCHl/SCCl/...", video "pIQT/MADk/...", etc) */ - block_samples = 0; /* layout ignores this */ - break; - } - - /* "SCHl" start block (movie "SHxx" shouldn't use multi files) */ - if (block_id == 0x5343486C) - new_schl = 1; - - /* padding between "SCEl" and next "SCHl" (when subfiles exist) */ - if (block_id == 0x00000000) - block_size = 0x04; - - /* guard against errors (happens in bad rips/endianness, observed max is vid ~0x20000) */ - if (block_size == 0x00 || block_size > 0xFFFFF || block_samples > 0xFFFF) { - block_size = 0x04; - block_samples = 0; - } - - /* "SCEl" end chunk should be 32b-aligned, fixes some multi-SCHl [ex. Need for Speed 2 (PC) .eam] */ - if (((block_offset + block_size) % 0x04) && block_id == 0x5343456C) { - block_size += 0x04 - ((block_offset + block_size) % 0x04); - } - } - - - /* set new channel offsets and ADPCM history */ - /* ADPCM hist could be considered part of the stream/decoder (some EAXA decoders call it "EAXA R1" when it has hist), and BNKs - * (with no blocks) may also have them in the first offset, but also may not. To simplify we just read them here. */ - switch(vgmstream->coding_type) { - /* id, size, unk1, unk2, interleaved data */ - case coding_PSX: - for (i = 0; i < vgmstream->channels; i++) { - size_t interleave = (block_size-0x10) / vgmstream->channels; - vgmstream->ch[i].offset = block_offset + 0x10 + i*interleave; - } - /* 0x08/0x0c: unknown (doesn't look like hist or offsets, as 1ch files has them too) */ - - break; - - /* id, size, IMA hist, stereo/mono data */ - case coding_DVI_IMA: - for(i = 0; i < vgmstream->channels; i++) { - off_t header_offset = block_offset + 0xc + i*4; - vgmstream->ch[i].adpcm_history1_32 = read_16bitLE(header_offset+0x00, vgmstream->ch[i].streamfile); - vgmstream->ch[i].adpcm_step_index = read_16bitLE(header_offset+0x02, vgmstream->ch[i].streamfile); - vgmstream->ch[i].offset = block_offset + 0xc + (4*vgmstream->channels); - } - - break; - - /* id, size, samples */ - case coding_PCM16_int: - for (i = 0; i < vgmstream->channels; i++) { - vgmstream->ch[i].offset = block_offset + 0x0c + (i*0x02); - } - - break; - - /* id, size, samples, hists-per-channel, stereo/interleaved data */ - case coding_EA_XA: - //case coding_EA_XA_V2: /* handled in default */ - case coding_EA_XA_int: - for (i = 0; i < vgmstream->channels; i++) { - int is_interleaved = vgmstream->coding_type == coding_EA_XA_int; - size_t interleave; - - /* read ADPCM history from all channels before data (not actually read in sx.exe) */ - //vgmstream->ch[i].adpcm_history1_32 = read_16bit(block_offset + 0x0C + (i*0x04) + 0x00,streamFile); - //vgmstream->ch[i].adpcm_history2_32 = read_16bit(block_offset + 0x0C + (i*0x04) + 0x02,streamFile); - - /* the block can have padding so find the channel size from num_samples */ - interleave = is_interleaved ? (block_samples / 28 * 0x0f) : 0; - - /* NOT channels*0x04, as seen in Superbike 2000 (PC) EA-XA v1 mono vids */ - vgmstream->ch[i].offset = block_offset + 0x0c + 2*0x04 + i*interleave; - } - - break; - - /* id, size, samples, offsets-per-channel, flag (0x01 = data start), data */ - case coding_EA_MT: - for (i = 0; i < vgmstream->channels; i++) { - off_t channel_start = read_32bit(block_offset + 0x0C + (0x04*i),streamFile); - vgmstream->ch[i].offset = block_offset + 0x0C + (0x04*vgmstream->channels) + channel_start + 0x01; - } - - /* flush decoder in every block change */ - flush_ea_mt(vgmstream); - break; - -#ifdef VGM_USE_MPEG - /* id, size, samples, offsets, unknown (null for MP2, some size/config for EALayer3; only if not >2ch) */ - case coding_MPEG_custom: - case coding_MPEG_layer1: - case coding_MPEG_layer2: - case coding_MPEG_layer3: - case coding_MPEG_ealayer3: - for (i = 0; i < vgmstream->channels; i++) { - off_t channel_start; - - /* EALayer3 6ch uses 1ch*6 with offsets, no flag in header [Medal of Honor 2010 (PC) movies] */ - if (vgmstream->channels > 2) { - channel_start = read_32bit(block_offset + 0x0C + 0x04*i,streamFile); - } else { - channel_start = read_32bit(block_offset + 0x0C,streamFile); - } - - vgmstream->ch[i].offset = block_offset + 0x0C + (0x04*vgmstream->channels) + channel_start; - } - - /* SCHl with multiple SCHl need to reset their MPEG decoder as there are trailing samples in the buffers */ - if (new_schl) { - flush_mpeg(vgmstream->codec_data); - } - - break; -#endif - /* id, size, samples, offsets-per-channel, interleaved data (w/ optional hist per channel) */ - default: - for (i = 0; i < vgmstream->channels; i++) { - off_t channel_start = read_32bit(block_offset + 0x0C + (0x04*i),streamFile); - vgmstream->ch[i].offset = block_offset + 0x0C + (0x04*vgmstream->channels) + channel_start; - } - - /* read ADPCM history before each channel if needed (not actually read in sx.exe) */ - if (vgmstream->codec_version == 1) { - for (i = 0; i < vgmstream->channels; i++) { - //vgmstream->ch[i].adpcm_history1_32 = read_16bit(vgmstream->ch[i].offset+0x00,streamFile); - //vgmstream->ch[i].adpcm_history3_32 = read_16bit(vgmstream->ch[i].offset+0x02,streamFile); - vgmstream->ch[i].offset += 4; - } - } - - break; - } - - vgmstream->current_block_offset = block_offset; - vgmstream->next_block_offset = block_offset + block_size; - vgmstream->current_block_samples = block_samples; - vgmstream->current_block_size = 0; /* uses current_block_samples instead */ -} +#include "layout.h" +#include "../coding/coding.h" +#include "../vgmstream.h" + +/* parse EA style blocks, id+size+samples+data */ +void block_update_ea_schl(off_t block_offset, VGMSTREAM * vgmstream) { + STREAMFILE* streamFile = vgmstream->ch[0].streamfile; + int i; + int new_schl = 0; + size_t block_size, block_samples; + int32_t (*read_32bit)(off_t,STREAMFILE*) = vgmstream->codec_endian ? read_32bitBE : read_32bitLE; + + + /* EOF reads: signal we have nothing and let the layout fail */ + if (block_offset >= get_streamfile_size(streamFile)) { + vgmstream->current_block_offset = block_offset; + vgmstream->next_block_offset = block_offset; + vgmstream->current_block_samples = -1; + return; + } + + /* read a single block */ + { + uint32_t block_id = read_32bitBE(block_offset+0x00,streamFile); + + block_size = read_32bitLE(block_offset+0x04,streamFile); + if (block_size > 0x00F00000) /* size is always LE, except in early SAT/MAC */ + block_size = read_32bitBE(block_offset+0x04,streamFile); + + switch(block_id) { + case 0x5343446C: /* "SCDl" */ + case 0x5344454E: /* "SDEN" */ + case 0x53444652: /* "SDFR" */ + case 0x53444745: /* "SDGE" */ + case 0x53444954: /* "SDIT" */ + case 0x53445350: /* "SDSP" */ + case 0x53445255: /* "SDRU" */ + case 0x53444A41: /* "SDJA" */ + /* audio chunk */ + if (vgmstream->coding_type == coding_PSX) + block_samples = ps_bytes_to_samples(block_size-0x10, vgmstream->channels); + else + block_samples = read_32bit(block_offset+0x08,streamFile); + break; + default: + /* ignore other chunks (audio "SCHl/SCCl/...", video "pIQT/MADk/...", etc) */ + block_samples = 0; /* layout ignores this */ + break; + } + + /* "SCHl" start block (movie "SHxx" shouldn't use multi files) */ + if (block_id == 0x5343486C) + new_schl = 1; + + /* padding between "SCEl" and next "SCHl" (when subfiles exist) */ + if (block_id == 0x00000000) + block_size = 0x04; + + /* guard against errors (happens in bad rips/endianness, observed max is vid ~0x20000) */ + if (block_size == 0x00 || block_size > 0xFFFFF || block_samples > 0xFFFF) { + block_size = 0x04; + block_samples = 0; + } + + /* "SCEl" end chunk should be 32b-aligned, fixes some multi-SCHl [ex. Need for Speed 2 (PC) .eam] */ + if (((block_offset + block_size) % 0x04) && block_id == 0x5343456C) { + block_size += 0x04 - ((block_offset + block_size) % 0x04); + } + } + + + vgmstream->current_block_offset = block_offset; + vgmstream->next_block_offset = block_offset + block_size; + vgmstream->current_block_samples = block_samples; + vgmstream->current_block_size = 0; /* uses current_block_samples instead */ + + /* no need to setup offsets (plus could read over filesize near EOF) */ + if (block_samples == 0) + return; + + + /* set new channel offsets and ADPCM history */ + /* ADPCM hist could be considered part of the stream/decoder (some EAXA decoders call it "EAXA R1" when it has hist), and BNKs + * (with no blocks) may also have them in the first offset, but also may not. To simplify we just read them here. */ + switch(vgmstream->coding_type) { + /* id, size, unk1, unk2, interleaved data */ + case coding_PSX: + for (i = 0; i < vgmstream->channels; i++) { + size_t interleave = (block_size-0x10) / vgmstream->channels; + vgmstream->ch[i].offset = block_offset + 0x10 + i*interleave; + } + /* 0x08/0x0c: unknown (doesn't look like hist or offsets, as 1ch files has them too) */ + + break; + + /* id, size, IMA hist, stereo/mono data */ + case coding_DVI_IMA: + for(i = 0; i < vgmstream->channels; i++) { + off_t header_offset = block_offset + 0xc + i*4; + vgmstream->ch[i].adpcm_history1_32 = read_16bitLE(header_offset+0x00, vgmstream->ch[i].streamfile); + vgmstream->ch[i].adpcm_step_index = read_16bitLE(header_offset+0x02, vgmstream->ch[i].streamfile); + vgmstream->ch[i].offset = block_offset + 0xc + (4*vgmstream->channels); + } + + break; + + /* id, size, samples */ + case coding_PCM16_int: + for (i = 0; i < vgmstream->channels; i++) { + vgmstream->ch[i].offset = block_offset + 0x0c + (i*0x02); + } + + break; + + /* id, size, samples, hists-per-channel, stereo/interleaved data */ + case coding_EA_XA: + //case coding_EA_XA_V2: /* handled in default */ + case coding_EA_XA_int: + for (i = 0; i < vgmstream->channels; i++) { + int is_interleaved = vgmstream->coding_type == coding_EA_XA_int; + size_t interleave; + + /* read ADPCM history from all channels before data (not actually read in sx.exe) */ + //vgmstream->ch[i].adpcm_history1_32 = read_16bit(block_offset + 0x0C + (i*0x04) + 0x00,streamFile); + //vgmstream->ch[i].adpcm_history2_32 = read_16bit(block_offset + 0x0C + (i*0x04) + 0x02,streamFile); + + /* the block can have padding so find the channel size from num_samples */ + interleave = is_interleaved ? (block_samples / 28 * 0x0f) : 0; + + /* NOT channels*0x04, as seen in Superbike 2000 (PC) EA-XA v1 mono vids */ + vgmstream->ch[i].offset = block_offset + 0x0c + 2*0x04 + i*interleave; + } + + break; + + /* id, size, samples, offsets-per-channel, flag (0x01 = data start), data */ + case coding_EA_MT: + for (i = 0; i < vgmstream->channels; i++) { + off_t channel_start = read_32bit(block_offset + 0x0C + (0x04*i),streamFile); + vgmstream->ch[i].offset = block_offset + 0x0C + (0x04*vgmstream->channels) + channel_start + 0x01; + } + + /* flush decoder in every block change */ + flush_ea_mt(vgmstream); + break; + +#ifdef VGM_USE_MPEG + /* id, size, samples, offsets, unknown (null for MP2, some size/config for EALayer3; only if not >2ch) */ + case coding_MPEG_custom: + case coding_MPEG_layer1: + case coding_MPEG_layer2: + case coding_MPEG_layer3: + case coding_MPEG_ealayer3: + for (i = 0; i < vgmstream->channels; i++) { + off_t channel_start; + + /* EALayer3 6ch uses 1ch*6 with offsets, no flag in header [Medal of Honor 2010 (PC) movies] */ + if (vgmstream->channels > 2) { + channel_start = read_32bit(block_offset + 0x0C + 0x04*i,streamFile); + } else { + channel_start = read_32bit(block_offset + 0x0C,streamFile); + } + + vgmstream->ch[i].offset = block_offset + 0x0C + (0x04*vgmstream->channels) + channel_start; + } + + /* SCHl with multiple SCHl need to reset their MPEG decoder as there are trailing samples in the buffers */ + if (new_schl) { + flush_mpeg(vgmstream->codec_data); + } + + break; +#endif + /* id, size, samples, offsets-per-channel, interleaved data (w/ optional hist per channel) */ + default: + for (i = 0; i < vgmstream->channels; i++) { + off_t channel_start = read_32bit(block_offset + 0x0C + (0x04*i),streamFile); + vgmstream->ch[i].offset = block_offset + 0x0C + (0x04*vgmstream->channels) + channel_start; + } + + /* read ADPCM history before each channel if needed (not actually read in sx.exe) */ + if (vgmstream->codec_version == 1) { + for (i = 0; i < vgmstream->channels; i++) { + //vgmstream->ch[i].adpcm_history1_32 = read_16bit(vgmstream->ch[i].offset+0x00,streamFile); + //vgmstream->ch[i].adpcm_history3_32 = read_16bit(vgmstream->ch[i].offset+0x02,streamFile); + vgmstream->ch[i].offset += 4; + } + } + + break; + } +} diff --git a/Frameworks/vgmstream/vgmstream/src/layout/blocked_ivaud.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_ivaud.c index 3a950e31a..2349dbb15 100644 --- a/Frameworks/vgmstream/vgmstream/src/layout/blocked_ivaud.c +++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked_ivaud.c @@ -1,25 +1,53 @@ #include "layout.h" #include "../vgmstream.h" -/* set up for the block at the given offset */ +/* GTA IV blocks */ void block_update_ivaud(off_t block_offset, VGMSTREAM * vgmstream) { + STREAMFILE *streamFile = vgmstream->ch[0].streamfile; + size_t header_size, block_samples; int i; - off_t start_offset; - off_t interleave_size; - int32_t nextFrame=0; - STREAMFILE *streamFile=vgmstream->ch[0].streamfile; + off_t seek_info_offset; - vgmstream->current_block_offset = block_offset; + /* base header */ + seek_info_offset = read_32bitLE(block_offset+0x00,streamFile); /*64b */ + /* 0x08(8): seek table offset */ + /* 0x10(8): seek table offset again? */ - nextFrame=(read_32bitLE(vgmstream->current_block_offset+0x28,streamFile)<<12)+0x800; + /* seek info (per channel) */ + /* 0x00: start entry */ + /* 0x04: number of entries */ + /* 0x08: unknown */ + /* 0x0c: data size */ - vgmstream->next_block_offset = vgmstream->current_block_offset + nextFrame; - vgmstream->current_block_size=read_32bitLE(block_offset+0x24,streamFile)/2; + /* seek table (per all entries) */ + /* 0x00: start? */ + /* 0x04: end? */ - start_offset=vgmstream->current_block_offset + 0x800; - interleave_size=(read_32bitLE(block_offset+0x28,streamFile)<<12)/2; - for(i=0;ichannels;i++) { - vgmstream->ch[i].offset = start_offset + (i*interleave_size); - } + /* find header size */ + /* can't see a better way to calc, as there may be dummy entries after usable ones + * (table is max 0x7b8 + seek table offset + 0x800-padded) */ + if (vgmstream->channels > 3) + header_size = 0x1000; + else + header_size = 0x800; + + /* get max data_size as channels may vary slightly (data is padded, hopefully won't create pops) */ + block_samples = 0; + for(i = 0;i < vgmstream->channels; i++) { + size_t channel_samples = read_32bitLE(block_offset + seek_info_offset+0x0c + 0x10*i,streamFile); + if (block_samples < channel_samples) + block_samples = channel_samples; + } + + vgmstream->current_block_offset = block_offset; + vgmstream->next_block_offset = block_offset + vgmstream->full_block_size; + vgmstream->current_block_samples = block_samples; + vgmstream->current_block_size = 0; + + for(i = 0; i < vgmstream->channels; i++) { + /* use seek table's start entry to find channel offset */ + size_t interleave_size = read_32bitLE(block_offset + seek_info_offset+0x00 + 0x10*i,streamFile) * 0x800; + vgmstream->ch[i].offset = block_offset + header_size + interleave_size; + } } diff --git a/Frameworks/vgmstream/vgmstream/src/layout/blocked_ps2_strlr.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_ps2_strlr.c index d2834db50..17f982bb6 100644 --- a/Frameworks/vgmstream/vgmstream/src/layout/blocked_ps2_strlr.c +++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked_ps2_strlr.c @@ -1,19 +1,17 @@ #include "layout.h" #include "../vgmstream.h" -/* set up for the block at the given offset */ +/* The Bouncer STRx blocks, one block per channel when stereo */ void block_update_ps2_strlr(off_t block_offset, VGMSTREAM * vgmstream) { + STREAMFILE* streamFile = vgmstream->ch[0].streamfile; int i; - vgmstream->current_block_offset = block_offset; - vgmstream->current_block_size = read_32bitLE( - vgmstream->current_block_offset+0x4, - vgmstream->ch[0].streamfile)*2; - vgmstream->next_block_offset = vgmstream->current_block_offset+vgmstream->current_block_size+0x40; - //vgmstream->current_block_size/=vgmstream->channels; + vgmstream->current_block_offset = block_offset; + vgmstream->current_block_size = read_32bitLE(block_offset+0x04,streamFile); /* can be smaller than 0x800 */ + vgmstream->next_block_offset = block_offset + 0x800*vgmstream->channels; + /* 0x08: number of remaning blocks, 0x10: some id/size? (shared in all blocks) */ - for (i=0;ichannels;i++) { - vgmstream->ch[i].offset = vgmstream->current_block_offset+0x20+(0x800*i); - + for (i = 0; i < vgmstream->channels; i++) { + vgmstream->ch[i].offset = block_offset + 0x20 + 0x800*i; } } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ahx.c b/Frameworks/vgmstream/vgmstream/src/meta/ahx.c index 595707504..be434451c 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ahx.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ahx.c @@ -48,9 +48,8 @@ VGMSTREAM * init_vgmstream_ahx(STREAMFILE *streamFile) { { #ifdef VGM_USE_MPEG - mpeg_custom_config cfg; + mpeg_custom_config cfg = {0}; - memset(&cfg, 0, sizeof(mpeg_custom_config)); cfg.encryption = read_8bit(0x13,streamFile); /* 0x08 = keyword encryption */ cfg.cri_type = type; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/awc.c b/Frameworks/vgmstream/vgmstream/src/meta/awc.c index 1994613a6..2990c772c 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/awc.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/awc.c @@ -28,7 +28,7 @@ static int parse_awc_header(STREAMFILE* streamFile, awc_header* awc); /* AWC - from RAGE (Rockstar Advanced Game Engine) audio (Red Dead Redemption, Max Payne 3, GTA5) */ VGMSTREAM * init_vgmstream_awc(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - awc_header awc; + awc_header awc = {0}; /* check extension */ if (!check_extensions(streamFile,"awc")) @@ -137,8 +137,7 @@ VGMSTREAM * init_vgmstream_awc(STREAMFILE *streamFile) { #endif #ifdef VGM_USE_MPEG case 0x07: { /* MPEG (PS3) */ - mpeg_custom_config cfg; - memset(&cfg, 0, sizeof(mpeg_custom_config)); + mpeg_custom_config cfg = {0}; cfg.chunk_size = awc.block_chunk; cfg.big_endian = awc.big_endian; @@ -183,8 +182,6 @@ static int parse_awc_header(STREAMFILE* streamFile, awc_header* awc) { off_t off; int target_subsong = streamFile->stream_index; - memset(awc,0,sizeof(awc_header)); - /* check header */ if (read_32bitBE(0x00,streamFile) != 0x41444154 && /* "ADAT" (LE) */ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/bik.c b/Frameworks/vgmstream/vgmstream/src/meta/bik.c index 3e3595762..18a3996d3 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/bik.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/bik.c @@ -36,8 +36,8 @@ VGMSTREAM * init_vgmstream_bik(STREAMFILE *streamFile) { #ifdef VGM_USE_FFMPEG { - ffmpeg_custom_config cfg; - memset(&cfg, 0, sizeof(ffmpeg_custom_config)); + ffmpeg_custom_config cfg = {0}; + cfg.stream_index = stream_index; vgmstream->codec_data = init_ffmpeg_config(streamFile, NULL,0, 0x0,get_streamfile_size(streamFile), &cfg); diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ea_eaac.c b/Frameworks/vgmstream/vgmstream/src/meta/ea_eaac.c index 01f24a562..bf417b9eb 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ea_eaac.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ea_eaac.c @@ -108,22 +108,26 @@ fail: return NULL; } -/* .SPS? - from Frostbite engine games? [Need for Speed Rivals (PS4)], v1 header */ +/* .SPS - from Frostbite engine games, v1 header */ VGMSTREAM * init_vgmstream_ea_sps_fb(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; off_t start_offset = 0, header_offset = 0, sps_offset, max_offset; /* checks */ - /* assumed to be .sps (no extensions in the archives) */ + /* should be .sps once extracted (filenames are hashed) */ if (!check_extensions(streamFile,"sps")) goto fail; - if (read_32bitBE(0x00,streamFile) != 0x011006C0) + if (read_32bitBE(0x00,streamFile) != 0x011006C0 && /* Need for Speed: The Run (PS3), Need for Speed: Rivals (PS4) */ + read_32bitBE(0x00,streamFile) != 0x01100180 && /* Need for Speed: The Run (X360) */ + read_32bitBE(0x00,streamFile) != 0x01100000) /* Need for Speed: The Run (PC) */ goto fail; + /* file has a Frostbite descriptor (SoundWaveAsset segments) data before actual .sps, exact size unknown. + * 0x00: segments/flags/sizes? 0x04: SegmentLength?, 0x08: SeekTableOffset?, 0x0c: mini SPS header + * rest: unknown fields? may be padded? (ex. 0x22 > 0x24, 0x1d > 0x20 */ - /* file has some kind of data before .sps, exact offset unknown. - * Actual offsets are probably somewhere but for now just manually search. */ - sps_offset = read_32bitBE(0x08, streamFile); /* points to some kind of table, number of entries unknown */ + /* actual offsets are probably somewhere but for now just manually search. */ + sps_offset = read_32bitBE(0x08, streamFile); /* seek table, number of entries unknown */ max_offset = sps_offset + 0x3000; if (max_offset > get_streamfile_size(streamFile)) max_offset = get_streamfile_size(streamFile); @@ -171,7 +175,7 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST /* rest is optional, depends on flags header used (ex. SNU and SPS may have bigger headers): * &0x20: 1 int (usually 0x00), &0x00/40: nothing, &0x60: 2 ints (usually 0x00 and 0x14) */ - /* V0: SNR+SNS, V1: SPR+SPS (not apparent differences, other than the block flags used) */ + /* V0: SNR+SNS, V1: SPR+SPS (no apparent differences, other than the block flags used) */ if (version != 0 && version != 1) { VGM_LOG("EA SNS/SPS: unknown version\n"); goto fail; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ea_eaac_streamfile.h b/Frameworks/vgmstream/vgmstream/src/meta/ea_eaac_streamfile.h index 4ecb24bfb..9436af00d 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ea_eaac_streamfile.h +++ b/Frameworks/vgmstream/vgmstream/src/meta/ea_eaac_streamfile.h @@ -39,7 +39,7 @@ static size_t eaac_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, off_t intrablock_offset, intradata_offset; uint32_t block_flag, block_size, data_size, skip_size; - block_flag = read_8bit(data->physical_offset+0x00,streamfile); + block_flag = (uint8_t)read_8bit(data->physical_offset+0x00,streamfile); block_size = read_32bitBE(data->physical_offset+0x00,streamfile) & 0x00FFFFFF; if (data->version == 1 && block_flag == 0x48) { @@ -47,7 +47,7 @@ static size_t eaac_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, continue; /* skip header block */ } if (data->version == 1 && block_flag == 0x45) - return total_read; /* stop on last block (always empty) */ + break; /* stop on last block (always empty) */ switch(data->codec) { #if 0 @@ -92,13 +92,13 @@ static size_t eaac_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, if (to_read > length) to_read = length; if (to_read == 0) - return total_read; /* should never happen... */ + break; /* should never happen... */ /* finally read and move buffer/offsets */ bytes_read = read_streamfile(dest, data->physical_offset + intrablock_offset, to_read, streamfile); total_read += bytes_read; if (bytes_read != to_read) - return total_read; /* couldn't read fully */ + break; /* couldn't read fully */ dest += bytes_read; offset += bytes_read; @@ -131,7 +131,7 @@ static size_t eaac_io_size(STREAMFILE *streamfile, eaac_io_data* data) { while (physical_offset < max_physical_offset) { uint32_t block_flag, block_size, data_size; - block_flag = read_8bit(physical_offset+0x00,streamfile); + block_flag = (uint8_t)read_8bit(physical_offset+0x00,streamfile); block_size = read_32bitBE(physical_offset+0x00,streamfile) & 0x00FFFFFF; if (data->version == 0 && block_flag != 0x00 && block_flag != 0x80) diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ea_schl.c b/Frameworks/vgmstream/vgmstream/src/meta/ea_schl.c index 86b613417..84db214f3 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ea_schl.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ea_schl.c @@ -10,7 +10,7 @@ #define EA_VERSION_V3 0x03 // ~PS2 era /* platform constants (unasigned values seem internal only) */ -#define EA_PLATFORM_GENERIC -1 // typically Wii/X360/PS3 +#define EA_PLATFORM_GENERIC -1 // typically Wii/X360/PS3/videos #define EA_PLATFORM_PC 0x00 #define EA_PLATFORM_PSX 0x01 #define EA_PLATFORM_N64 0x02 @@ -21,6 +21,7 @@ #define EA_PLATFORM_XBOX 0x07 #define EA_PLATFORM_X360 0x09 // also "Xenon" #define EA_PLATFORM_PSP 0x0A +#define EA_PLATFORM_PS3 0x0E // very rare [Need for Speed: Carbon (PS3)] #define EA_PLATFORM_3DS 0x14 /* codec constants (undefined are probably reserved, ie.- sx.exe encodes PCM24/DVI but no platform decodes them) */ @@ -350,11 +351,19 @@ static VGMSTREAM * init_vgmstream_ea_variable_header(STREAMFILE *streamFile, ea_ #endif case EA_CODEC2_MT10: /* MicroTalk (10:1 compression) */ - case EA_CODEC2_MT5: /* MicroTalk (5:1 compression) */ + case EA_CODEC2_MT5: { /* MicroTalk (5:1 compression) */ + int use_pcm_blocks = 0; + + if (ea->version == EA_VERSION_V3 || (ea->version == EA_VERSION_V2 && + (ea->platform == EA_PLATFORM_PC || ea->platform == EA_PLATFORM_MAC))) { + use_pcm_blocks = 1; + } + vgmstream->coding_type = coding_EA_MT; - vgmstream->codec_data = init_ea_mt(vgmstream->channels, ea->version == EA_VERSION_V3); + vgmstream->codec_data = init_ea_mt(vgmstream->channels, use_pcm_blocks); if (!vgmstream->codec_data) goto fail; break; + } case EA_CODEC2_ATRAC3PLUS: /* regular ATRAC3plus chunked in SCxx blocks, including RIFF header */ default: @@ -509,6 +518,7 @@ static int parse_variable_header(STREAMFILE* streamFile, ea_header* ea, off_t be case 0x13: /* effect bus (0..127) */ case 0x14: /* emdedded user data (free size/value) */ case 0x19: /* related to playback envelope (BNK only) */ + case 0x1A: /* unknown and very rare, size 0 (BNK only) [SSX3 (PS2)] */ case 0x1B: /* unknown (movie only?) */ case 0x1C: /* initial envelope volume (BNK only) */ case 0x24: /* master random detune range (BNK only) */ @@ -608,7 +618,7 @@ static int parse_variable_header(STREAMFILE* streamFile, ea_header* ea, off_t be case 0x9F: /* azimuth ch4 */ case 0xA6: /* azimuth ch5 */ case 0xA7: /* azimuth ch6 */ - case 0xA1: /* unknown and very rare, always 0x02 (FIFA 2001 PS2) */ + case 0xA1: /* unknown and very rare, always 0x02 [FIFA 2001 (PS2)] */ read_patch(streamFile, &offset); break; @@ -636,6 +646,7 @@ static int parse_variable_header(STREAMFILE* streamFile, ea_header* ea, off_t be || ea->platform == EA_PLATFORM_SAT || ea->platform == EA_PLATFORM_GC_WII || ea->platform == EA_PLATFORM_X360 + || ea->platform == EA_PLATFORM_PS3 || ea->platform == EA_PLATFORM_GENERIC) { ea->big_endian = 1; } @@ -658,6 +669,7 @@ static int parse_variable_header(STREAMFILE* streamFile, ea_header* ea, off_t be case EA_PLATFORM_XBOX: ea->version = EA_VERSION_V2; break; case EA_PLATFORM_X360: ea->version = EA_VERSION_V3; break; case EA_PLATFORM_PSP: ea->version = EA_VERSION_V3; break; + case EA_PLATFORM_PS3: ea->version = EA_VERSION_V3; break; case EA_PLATFORM_3DS: ea->version = EA_VERSION_V3; break; case EA_PLATFORM_GENERIC: ea->version = EA_VERSION_V2; break; default: @@ -707,6 +719,7 @@ static int parse_variable_header(STREAMFILE* streamFile, ea_header* ea, off_t be case EA_PLATFORM_XBOX: ea->codec2 = EA_CODEC2_S16LE; break; case EA_PLATFORM_X360: ea->codec2 = EA_CODEC2_EAXA; break; case EA_PLATFORM_PSP: ea->codec2 = EA_CODEC2_EAXA; break; + case EA_PLATFORM_PS3: ea->codec2 = EA_CODEC2_EAXA; break; case EA_PLATFORM_3DS: ea->codec2 = EA_CODEC2_GCADPCM; break; default: VGM_LOG("EA SCHl: unknown default codec2 for platform 0x%02x\n", ea->platform); @@ -728,6 +741,7 @@ static int parse_variable_header(STREAMFILE* streamFile, ea_header* ea, off_t be case EA_PLATFORM_XBOX: ea->sample_rate = 24000; break; case EA_PLATFORM_X360: ea->sample_rate = 44100; break; case EA_PLATFORM_PSP: ea->sample_rate = 22050; break; + case EA_PLATFORM_PS3: ea->sample_rate = 44100; break; //case EA_PLATFORM_3DS: ea->sample_rate = 44100; break;//todo (not 22050/16000) default: VGM_LOG("EA SCHl: unknown default sample rate for platform 0x%02x\n", ea->platform); diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ea_schl_fixed.c b/Frameworks/vgmstream/vgmstream/src/meta/ea_schl_fixed.c index 1b56893ec..1703c0adf 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ea_schl_fixed.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ea_schl_fixed.c @@ -26,7 +26,7 @@ VGMSTREAM * init_vgmstream_ea_schl_fixed(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; off_t start_offset; size_t header_size; - ea_header ea; + ea_header ea = {0}; /* check extension */ @@ -94,8 +94,6 @@ fail: static int parse_fixed_header(STREAMFILE* streamFile, ea_header* ea, off_t begin_offset) { off_t offset = begin_offset; - memset(ea,0,sizeof(ea_header)); - if (read_32bitBE(offset+0x00, streamFile) != 0x5041546C && /* "PATl" */ read_32bitBE(offset+0x38, streamFile) != 0x544D706C) /* "TMpl" */ goto fail; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/fsb5.c b/Frameworks/vgmstream/vgmstream/src/meta/fsb5.c index da2c2f414..0a0526ac0 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/fsb5.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/fsb5.c @@ -34,8 +34,10 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) { * type 0x00 has an extra field (always 0?) at 0x1c */ BaseHeaderLength = (Version==0x00) ? 0x40 : 0x3C; - if ((SampleHeaderLength + NameTableLength + SampleDataLength + BaseHeaderLength) != get_streamfile_size(streamFile)) + if ((SampleHeaderLength + NameTableLength + SampleDataLength + BaseHeaderLength) != get_streamfile_size(streamFile)) { + VGM_LOG("FSB5: bad size (%x + %x + %x + %x != %x)\n", SampleHeaderLength, NameTableLength, SampleDataLength, BaseHeaderLength, get_streamfile_size(streamFile)); goto fail; + } if (TargetSubsong == 0) TargetSubsong = 1; /* default to 1 */ if (TargetSubsong > TotalSubsongs || TotalSubsongs <= 0) goto fail; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h b/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h index c9f6362cb..f80c82243 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h +++ b/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h @@ -238,7 +238,13 @@ static const hcakey_info hcakey_list[] = { {3201512}, // 000000000030D9E8 // PriPara: All Idol Perfect Stage (Takara Tomy) [Switch] - {217735759}, // 000000000CFA624F + {217735759}, // 000000000CFA624F + + // Space Invaders Extreme (Taito Corporation, Backbone Entertainment) [PC] + {91380310056}, // 0000001546B0E028 + + // CR Another God Hades Advent (Universal Entertainment Corporation) [iOS/Android] + {64813795}, // 0000000003DCFAE3 }; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ivaud.c b/Frameworks/vgmstream/vgmstream/src/meta/ivaud.c index 5584dc318..96efa6701 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ivaud.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ivaud.c @@ -2,67 +2,195 @@ #include "../layout/layout.h" #include "../util.h" -/* ivaud (from GTA IV (PC)) */ +typedef struct { + int is_music; + + int total_subsongs; + + int channel_count; + int sample_rate; + int codec; + int num_samples; + + size_t block_count; + size_t block_size; + + off_t stream_offset; + size_t stream_size; + +} ivaud_header; + +static int parse_ivaud_header(STREAMFILE* streamFile, ivaud_header* ivaud); + + +/* .ivaud - from GTA IV (PC) */ VGMSTREAM * init_vgmstream_ivaud(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; + ivaud_header ivaud = {0}; + int loop_flag; - char filename[PATH_LIMIT]; - off_t start_offset; - off_t block_table_offset; - int loop_flag = 0; - int channel_count; - int i; + /* checks */ + /* (hashed filenames are likely extensionless and .ivaud is added by tools) */ + if (!check_extensions(streamFile, "ivaud,")) + goto fail; + + /* check header */ + if (!parse_ivaud_header(streamFile, &ivaud)) + goto fail; - /* at this time, i only check for extension */ - /* i'll make further checks later */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("ivaud",filename_extension(filename))) goto fail; - - /* multiple sounds .ivaud files are not implemented */ - /* only used for voices & sfx */ - if(read_32bitLE(0x10,streamFile)!=0) - goto fail; - - /* never looped and allways 2 channels */ loop_flag = 0; - channel_count = 2; - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(ivaud.channel_count,loop_flag); if (!vgmstream) goto fail; - /* fill in the vital statistics */ - block_table_offset = read_32bitLE(0,streamFile); - vgmstream->channels = channel_count; - vgmstream->sample_rate = read_32bitLE(block_table_offset + 0x04,streamFile); - vgmstream->coding_type = coding_IMA_int; + vgmstream->sample_rate = ivaud.sample_rate; + vgmstream->num_samples = ivaud.num_samples; + vgmstream->num_streams = ivaud.total_subsongs; + vgmstream->stream_size = ivaud.stream_size; + vgmstream->meta_type = meta_IVAUD; - vgmstream->layout_type = layout_blocked_ivaud; - vgmstream->meta_type = meta_PC_IVAUD; + switch(ivaud.codec) { + case 0x0001: /* common in sfx, uncommon in music (ex. EP2_SFX/MENU_MUSIC) */ + vgmstream->coding_type = coding_PCM16LE; + vgmstream->layout_type = ivaud.is_music ? layout_blocked_ivaud : layout_none; + vgmstream->full_block_size = ivaud.block_size; + break; - /* open the file for reading */ - { - for (i=0;ich[i].streamfile = streamFile->open(streamFile,filename,0x2000); - if (!vgmstream->ch[i].streamfile) goto fail; - } + case 0x0400: + vgmstream->coding_type = coding_IMA_int; + vgmstream->layout_type = ivaud.is_music ? layout_blocked_ivaud : layout_none; + vgmstream->full_block_size = ivaud.block_size; + break; + + default: + VGM_LOG("IVAUD: unknown codec 0x%x\n", ivaud.codec); + goto fail; } - - /* Calc num_samples */ - start_offset = read_32bitLE(0x2C,streamFile); - //block_count = read_32bitLE(0x08,streamFile); - vgmstream->next_block_offset = read_32bitLE(0x2C,streamFile); - // to avoid troubles with "extra" samples - vgmstream->num_samples=((read_32bitLE(0x60,streamFile)/2)*2); - block_update_ivaud(start_offset,vgmstream); + if (!vgmstream_open_stream(vgmstream,streamFile,ivaud.stream_offset)) + goto fail; + + if (vgmstream->layout_type == layout_blocked_ivaud) + block_update_ivaud(ivaud.stream_offset, vgmstream); return vgmstream; - /* clean up anything we may have opened */ fail: - if (vgmstream) close_vgmstream(vgmstream); + close_vgmstream(vgmstream); return NULL; } + +/* Parse Rockstar's .ivaud header (much info from SparkIV). */ +static int parse_ivaud_header(STREAMFILE* streamFile, ivaud_header* ivaud) { + int target_subsong = streamFile->stream_index; + + + /* use bank's stream count to detect */ + ivaud->is_music = (read_32bitLE(0x10,streamFile) == 0); + + if (ivaud->is_music) { + off_t block_table_offset, channel_table_offset, channel_info_offset; + + /* music header */ + block_table_offset = read_32bitLE(0x00,streamFile); /* 64b */ + ivaud->block_count = read_32bitLE(0x08,streamFile); + ivaud->block_size = read_32bitLE(0x0c,streamFile); /* 64b, uses padded blocks */ + channel_table_offset = read_32bitLE(0x14,streamFile); /* 64b */ + /* 0x1c(8): block_table_offset again? */ + ivaud->channel_count = read_32bitLE(0x24,streamFile); + /* 0x28(4): unknown entries? */ + ivaud->stream_offset = read_32bitLE(0x2c,streamFile); + channel_info_offset = channel_table_offset + ivaud->channel_count*0x10; + + if ((ivaud->block_count * ivaud->block_size) + ivaud->stream_offset != get_streamfile_size(streamFile)) { + VGM_LOG("IVAUD: bad file size\n"); + goto fail; + } + + /* channel table (one entry per channel, points to channel info) */ + /* 0x00(8): offset within channel_info_offset */ + /* 0x08(4): hash */ + /* 0x0c(4): size */ + + /* channel info (one entry per channel) */ + /* 0x00(8): offset within data (should be 0) */ + /* 0x08(4): hash */ + /* 0x0c(4): half num_samples? */ + ivaud->num_samples = read_32bitLE(channel_info_offset+0x10,streamFile); + /* 0x14(4): unknown (-1) */ + /* 0x18(2): sample rate */ + /* 0x1a(2): unknown */ + ivaud->codec = read_32bitLE(channel_info_offset+0x1c,streamFile); + /* (when codec is IMA) */ + /* 0x20(8): adpcm states offset, 0x38: num states? (reference for seeks?) */ + /* rest: unknown data */ + + /* block table (one entry per block) */ + /* 0x00: data size processed up to this block (doesn't count block padding) */ + ivaud->sample_rate = read_32bitLE(block_table_offset + 0x04,streamFile); + /* sample_rate should agree with each channel in the channel table */ + + + ivaud->total_subsongs = 1; + ivaud->stream_size = get_streamfile_size(streamFile); + } + else { + off_t stream_table_offset, stream_info_offset, stream_entry_offset; + + /* bank header */ + stream_table_offset = read_32bitLE(0x00,streamFile); /* 64b */ + /* 0x08(8): header size? start offset? */ + ivaud->total_subsongs = read_32bitLE(0x10,streamFile); + /* 0x14(4): unknown */ + ivaud->stream_offset = read_32bitLE(0x18,streamFile); /* base start_offset */ + + if (target_subsong == 0) target_subsong = 1; + if (target_subsong < 0 || target_subsong > ivaud->total_subsongs || ivaud->total_subsongs < 1) goto fail; + + if (stream_table_offset != 0x1c) + goto fail; + stream_info_offset = stream_table_offset + 0x10*ivaud->total_subsongs; + + /* stream table (one entry per stream, points to stream info) */ + stream_entry_offset = read_32bitLE(stream_table_offset + 0x10*(target_subsong-1) + 0x00,streamFile); /* within stream info */ + /* 0x00(8): offset within stream_info_offset */ + /* 0x08(4): hash */ + /* 0x0c(4): size */ + + /* stream info (one entry per stream) */ + ivaud->stream_offset += read_32bitLE(stream_info_offset+stream_entry_offset+0x00,streamFile); /* 64b, within data */ + /* 0x08(4): hash */ + /* 0x0c(4): half num_samples? */ + ivaud->num_samples = read_32bitLE(stream_info_offset+stream_entry_offset+0x10,streamFile); + /* 0x14(4): unknown (-1) */ + ivaud->sample_rate = (uint16_t)read_16bitLE(stream_info_offset+stream_entry_offset+0x18,streamFile); + /* 0x1a(2): unknown */ + ivaud->codec = read_32bitLE(stream_info_offset+stream_entry_offset+0x1c,streamFile); + /* (when codec is IMA) */ + /* 0x20(8): adpcm states offset, 0x38: num states? (reference for seeks?) */ + /* rest: unknown data */ + + ivaud->channel_count = 1; + + /* ghetto size calculator (could substract offsets but streams are not ordered) */ + switch(ivaud->codec) { + case 0x0001: + ivaud->stream_size = ivaud->num_samples * 2; /* double 16b PCM */ + break; + case 0x0400: + ivaud->stream_size = ivaud->num_samples / 2; /* half nibbles */ + break; + default: + break; + } + } + + + return 1; +fail: + return 0; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/nds_rrds.c b/Frameworks/vgmstream/vgmstream/src/meta/nds_rrds.c index ac28b64cd..b43ad83d1 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/nds_rrds.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/nds_rrds.c @@ -1,66 +1,52 @@ #include "meta.h" -#include "../util.h" - -/* bxaimc - 2009-03-05 - - RRDS - found in Ridge Racer DS */ +#include "../coding/coding.h" +/* RRDS - from (some) NST games [Ridge Racer (DS), Metroid Prime Hunters - First Hunt (DS)] */ VGMSTREAM * init_vgmstream_nds_rrds(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - int channel_count; - int loop_flag; off_t start_offset; + int loop_flag, channel_count; - /* check extension, case insensitive (made-up extension) */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("rrds",filename_extension(filename))) goto fail; + /* checks */ + /* .rrds: made-up extension (files come from a bigfile and don't have filenames/extension) */ + if (!check_extensions(streamFile, ",rrds")) + goto fail; - /* check size */ - if ((read_32bitLE(0x0,streamFile)+0x18) != get_streamfile_size(streamFile)) - goto fail; + if ((read_32bitLE(0x00,streamFile)+0x18) != get_streamfile_size(streamFile)) + goto fail; - /* check type details */ - loop_flag = (read_32bitLE(0x14,streamFile) != 0); + loop_flag = (read_32bitLE(0x14,streamFile) != 0); //todo not correct for MPH: First Hunt? channel_count = 1; - - /* build the VGMSTREAM */ + start_offset = 0x1c; + + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; - /* fill in the vital statistics */ - start_offset = 0x1c; - vgmstream->num_samples = (read_32bitLE(0x0,streamFile)-start_offset) / channel_count * 2; - vgmstream->sample_rate = read_32bitLE(0x8,streamFile); - if (loop_flag) { - vgmstream->loop_start_sample = (read_32bitLE(0x14,streamFile)-start_offset) / channel_count * 2; - vgmstream->loop_end_sample = vgmstream->num_samples; - } - - vgmstream->coding_type = coding_IMA_int; + vgmstream->sample_rate = read_32bitLE(0x08,streamFile); + vgmstream->num_samples = ima_bytes_to_samples(read_32bitLE(0x00,streamFile)-start_offset,channel_count); + if (loop_flag) { + vgmstream->loop_start_sample = ima_bytes_to_samples(read_32bitLE(0x14,streamFile)-start_offset,channel_count); + vgmstream->loop_end_sample = vgmstream->num_samples; + } + vgmstream->meta_type = meta_NDS_RRDS; + vgmstream->coding_type = coding_IMA_int; vgmstream->layout_type = layout_none; - - /* open the file for reading */ { - STREAMFILE * file; - file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!file) goto fail; - vgmstream->ch[0].streamfile = file; - - vgmstream->ch[0].channel_start_offset= - vgmstream->ch[0].offset=start_offset; - /* one NDS IMA header for whole stream */ vgmstream->ch[0].adpcm_history1_16 = read_16bitLE(0x18,streamFile); vgmstream->ch[0].adpcm_step_index = read_16bitLE(0x1a,streamFile); - if (vgmstream->ch[0].adpcm_step_index < 0 || vgmstream->ch[0].adpcm_step_index > 88) goto fail; + if (vgmstream->ch[0].adpcm_step_index < 0 || vgmstream->ch[0].adpcm_step_index > 88) + goto fail; } - + + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + goto fail; return vgmstream; - /* clean up anything we may have opened */ fail: - if (vgmstream) close_vgmstream(vgmstream); + 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 93b3b955b..e4edf876e 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ogg_vorbis.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ogg_vorbis.c @@ -226,6 +226,28 @@ static void gwm_ogg_decryption_callback(void *ptr, size_t size, size_t nmemb, vo } } +static void mus_ogg_decryption_callback(void *ptr, size_t size, size_t nmemb, void *datasource) { + static const uint8_t key[16] = { + 0x21,0x4D,0x6F,0x01,0x20,0x4C,0x6E,0x02,0x1F,0x4B,0x6D,0x03,0x20,0x4C,0x6E,0x02 + }; + + size_t bytes_read = size*nmemb; + ogg_vorbis_streamfile * const ov_streamfile = datasource; + int i; + char *header_id = "OggS"; + + /* bytes are xor'd with key, first "OggS" is changed */ + for (i = 0; i < bytes_read; i++) { + if (ov_streamfile->offset+i < 0x04) { /* if decrypted gives "Mus " */ + ((uint8_t*)ptr)[i] = (uint8_t)header_id[(ov_streamfile->offset + i) % 4]; + } + else { + ((uint8_t*)ptr)[i] ^= key[(ov_streamfile->offset + i) % sizeof(key)]; + } + } +} + + /* Ogg Vorbis, by way of libvorbisfile; may contain loop comments */ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) { ogg_vorbis_meta_info_t ovmi = {0}; @@ -239,6 +261,7 @@ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) { int is_rpgmvo = 0; int is_eno = 0; int is_gwm = 0; + int is_mus = 0; /* check extension */ @@ -262,6 +285,8 @@ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) { is_eno = 1; } else if (check_extensions(streamFile,"gwm")) { /* .gwm: Adagio: Cloudburst (PC) */ is_gwm = 1; + } else if (check_extensions(streamFile,"mus")) { /* .mus: Redux - Dark Matters (PC) */ + is_mus = 1; } else { goto fail; } @@ -355,7 +380,6 @@ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) { start_offset = 0x01; } - /* check GWM [Adagio: Cloudburst (PC)], encrypted */ if (is_gwm) { ovmi.xor_value = 0x5D; @@ -363,6 +387,12 @@ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) { ovmi.meta_type = meta_OGG_GWM; } + /* check .mus [Redux - Dark Matters (PC)], encrypted */ + if (is_mus) { + ovmi.decryption_callback = mus_ogg_decryption_callback; + ovmi.meta_type = meta_OGG_MUS; + } + return init_vgmstream_ogg_vorbis_callbacks(streamFile, NULL, start_offset, &ovmi); @@ -399,8 +429,8 @@ VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, ov_callb /* test if this is a proper Ogg Vorbis file, with the current (from init_x) STREAMFILE */ { - OggVorbis_File temp_ovf; - ogg_vorbis_streamfile temp_streamfile; + OggVorbis_File temp_ovf = {0}; + ogg_vorbis_streamfile temp_streamfile = {0}; temp_streamfile.streamfile = streamFile; @@ -414,7 +444,6 @@ VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, ov_callb temp_streamfile.xor_value = ovmi->xor_value; /* open the ogg vorbis file for testing */ - memset(&temp_ovf, 0, sizeof(temp_ovf)); if (ov_test_callbacks(&temp_streamfile, &temp_ovf, NULL, 0, *callbacks_p)) goto fail; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ogl.c b/Frameworks/vgmstream/vgmstream/src/meta/ogl.c index 66587b82c..f7a2a26eb 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ogl.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ogl.c @@ -41,8 +41,7 @@ VGMSTREAM * init_vgmstream_ogl(STREAMFILE *streamFile) { #ifdef VGM_USE_VORBIS { - vorbis_custom_config cfg; - memset(&cfg, 0, sizeof(vorbis_custom_config)); + vorbis_custom_config cfg = {0}; vgmstream->layout_type = layout_none; vgmstream->coding_type = coding_VORBIS_custom; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/opus.c b/Frameworks/vgmstream/vgmstream/src/meta/opus.c index 60aef3572..6bcc119d1 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/opus.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/opus.c @@ -46,13 +46,12 @@ static VGMSTREAM * init_vgmstream_opus(STREAMFILE *streamFile, meta_t meta_type, { uint8_t buf[0x100]; size_t bytes; - ffmpeg_custom_config cfg; + ffmpeg_custom_config cfg = {0}; ffmpeg_codec_data *ffmpeg_data; bytes = ffmpeg_make_opus_header(buf,0x100, vgmstream->channels, skip, vgmstream->sample_rate); if (bytes <= 0) goto fail; - memset(&cfg, 0, sizeof(ffmpeg_custom_config)); cfg.type = FFMPEG_SWITCH_OPUS; ffmpeg_data = init_ffmpeg_config(streamFile, buf,bytes, start_offset,data_size, &cfg); diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps2_joe.c b/Frameworks/vgmstream/vgmstream/src/meta/ps2_joe.c index 988a10c43..02c51c954 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ps2_joe.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ps2_joe.c @@ -5,17 +5,14 @@ VGMSTREAM * init_vgmstream_ps2_joe(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; off_t start_offset; + int channel_count, loop_flag, sample_rate, num_samples; size_t file_size, data_size, unknown1, unknown2, interleave; - int loop_flag; - int channel_count; + /* checks */ if (!check_extensions(streamFile, "joe")) goto fail; - loop_flag = 1; - channel_count = 2; - file_size = get_streamfile_size(streamFile); data_size = read_32bitLE(0x04,streamFile); unknown1 = read_32bitLE(0x08,streamFile); @@ -48,14 +45,20 @@ VGMSTREAM * init_vgmstream_ps2_joe(STREAMFILE *streamFile) { start_offset = file_size - data_size; + channel_count = 2; + sample_rate = read_32bitLE(0x00,streamFile); + num_samples = ps_bytes_to_samples(data_size, channel_count); + + /* most songs simply repeat except a few jingles (PS-ADPCM flags are always set) */ + loop_flag = (num_samples > 20*sample_rate); /* in seconds */ + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; - vgmstream->sample_rate = read_32bitLE(0x00,streamFile); - vgmstream->coding_type = coding_PSX; - vgmstream->num_samples = ps_bytes_to_samples(data_size, channel_count); + vgmstream->sample_rate = sample_rate; + vgmstream->num_samples = num_samples; //todo improve, not working 100% with early .joe { @@ -103,6 +106,7 @@ VGMSTREAM * init_vgmstream_ps2_joe(STREAMFILE *streamFile) { } } + vgmstream->coding_type = coding_PSX; vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = interleave; vgmstream->meta_type = meta_PS2_JOE; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps2_strlr.c b/Frameworks/vgmstream/vgmstream/src/meta/ps2_strlr.c index 2003f3795..9e8a42c6f 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ps2_strlr.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ps2_strlr.c @@ -1,80 +1,57 @@ #include "meta.h" #include "../layout/layout.h" -#include "../util.h" +#include "../coding/coding.h" -/* STR: The Bouncer (PS2) */ +/* STR - The Bouncer (PS2) */ VGMSTREAM * init_vgmstream_ps2_strlr(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - int loop_flag = 0; - int channel_count; - int i; - off_t start_offset; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("str",filename_extension(filename))) goto fail; + int channel_count, loop_flag; + off_t start_offset; + + + /* checks */ + /* .vs: real extension (from .nam container) , .str: partial header id */ + if (!check_extensions(streamFile, "vs,str")) + goto fail; -#if 0 /* check header */ - if (read_32bitBE(0x00,streamFile) != 0x5354524C) /* "STRL" */ + if (!(read_32bitBE(0x000,streamFile) == 0x5354524C && /* "STRL" */ + read_32bitBE(0x800,streamFile) == 0x53545252) && /* "STRR" */ + read_32bitBE(0x00,streamFile) != 0x5354524D) /* "STRM" */ goto fail; - if (read_32bitBE(0x00,streamFile) != 0x53545252) /* "STRR" */ - goto fail; -#endif - /* don't hijack Sonic & Sega All Stars Racing X360 (xma) */ - if (read_32bitBE(0x00,streamFile) == 0x52494646) - goto fail; /* "RIFF"*/ - /* don't hijack Mad Dash Racing (Xbox) */ - if (read_32bitLE(0x0c,streamFile) == 1 - && read_32bitLE(0x010,streamFile) == 0 - && read_32bitLE(0x400,streamFile) == 0 - && read_32bitLE(0x7f0,streamFile) == 0) - goto fail; loop_flag = 0; - channel_count = 2; - - /* build the VGMSTREAM */ + channel_count = (read_32bitBE(0x00,streamFile) == 0x5354524D) ? 1 : 2; /* "STRM"=mono (voices) */ + start_offset = 0x00; + + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; - /* fill in the vital statistics */ - start_offset = 0x0; - vgmstream->channels = channel_count; - vgmstream->sample_rate = 48000; + vgmstream->sample_rate = 44100; vgmstream->coding_type = coding_PSX; vgmstream->layout_type = layout_blocked_ps2_strlr; - //vgmstream->interleave_block_size = read_32bitLE(0xC, streamFile); vgmstream->meta_type = meta_PS2_STRLR; - - /* open the file for reading by each channel */ + + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + goto fail; + + /* calc num_samples */ { - for (i=0;ich[i].streamfile = streamFile->open(streamFile, filename, 0x8000); - if (!vgmstream->ch[i].streamfile) goto fail; + vgmstream->next_block_offset = start_offset; + do { + block_update_ps2_strlr(vgmstream->next_block_offset,vgmstream); + vgmstream->num_samples += ps_bytes_to_samples(vgmstream->current_block_size, 1); } + while (vgmstream->next_block_offset < get_streamfile_size(streamFile)); } - /* Calc num_samples */ block_update_ps2_strlr(start_offset, vgmstream); - vgmstream->num_samples=0; - - do - { - vgmstream->num_samples += vgmstream->current_block_size * 14 / 16; - block_update_ps2_strlr(vgmstream->next_block_offset, vgmstream); - } while (vgmstream->next_block_offset < get_streamfile_size(streamFile)); - - block_update_ps2_strlr(start_offset, vgmstream); - return vgmstream; - /* clean up anything we may have opened */ fail: - if (vgmstream) close_vgmstream(vgmstream); + close_vgmstream(vgmstream); return NULL; } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps2_vpk.c b/Frameworks/vgmstream/vgmstream/src/meta/ps2_vpk.c index 2f1622b36..8709809da 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ps2_vpk.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ps2_vpk.c @@ -1,5 +1,5 @@ #include "meta.h" -#include "../util.h" +#include "../coding/coding.h" /* VPK */ @@ -34,7 +34,7 @@ VGMSTREAM * init_vgmstream_ps2_vpk(STREAMFILE *streamFile) { /* Check for Compression Scheme */ vgmstream->coding_type = coding_PSX; - vgmstream->num_samples = read_32bitLE(0x04,streamFile)/16*28; + vgmstream->num_samples = ps_bytes_to_samples(read_32bitLE(0x04,streamFile),vgmstream->channels); /* Get loop point values */ if(vgmstream->loop_flag) { @@ -42,7 +42,7 @@ VGMSTREAM * init_vgmstream_ps2_vpk(STREAMFILE *streamFile) { vgmstream->loop_end_sample = vgmstream->num_samples; } - vgmstream->interleave_block_size = read_32bitLE(0x0C,streamFile)/2; + vgmstream->interleave_block_size = read_32bitLE(0x0C,streamFile)/vgmstream->channels; vgmstream->layout_type = layout_interleave; vgmstream->meta_type = meta_PS2_VPK; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/sk_aud.c b/Frameworks/vgmstream/vgmstream/src/meta/sk_aud.c index 6dd60a777..c39633c2f 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/sk_aud.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/sk_aud.c @@ -32,8 +32,7 @@ VGMSTREAM * init_vgmstream_sk_aud(STREAMFILE *streamFile) { #ifdef VGM_USE_VORBIS { - vorbis_custom_config cfg; - memset(&cfg, 0, sizeof(vorbis_custom_config)); + vorbis_custom_config cfg = {0}; vgmstream->layout_type = layout_none; vgmstream->coding_type = coding_VORBIS_custom; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ubi_sb.c b/Frameworks/vgmstream/vgmstream/src/meta/ubi_sb.c index 5b9c33395..ec39684e9 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ubi_sb.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ubi_sb.c @@ -313,6 +313,7 @@ static int parse_sb_header(ubi_sb_header * sb, STREAMFILE *streamFile) { /* ignore non-audio entry (other types seem to have config data) */ if (read_32bit(offset + 0x04, streamFile) != 0x01) continue; + //;VGM_LOG("SB at %lx\n", offset); /* weird case when there is no internal substream ID and just seem to rotate every time type changes, joy */ if (sb->has_rotating_ids) { /* assumes certain configs can't happen in this case */ @@ -779,6 +780,23 @@ static int config_sb_header_version(ubi_sb_header * sb, STREAMFILE *streamFile) return 1; } +#if 0 + /* Far cry: Instincts - Evolution (2006)(Xbox) */ + if (sb->version == 0x00170000 && is_sb2) { + sb->section1_entry_size = 0x48; + sb->section2_entry_size = 0x6c; + + sb->external_flag_offset = 0; + sb->num_samples_offset = 0x28; + sb->stream_id_offset = 0; + sb->sample_rate_offset = 0x3c; + sb->channels_offset = 0x44; + sb->stream_type_offset = 0x48; + sb->extra_name_offset = 0x58; + + return 1; + } +#endif /* Prince of Persia: Rival Swords (2007)(PSP) */ if (sb->version == 0x00180005 && is_sb5) { diff --git a/Frameworks/vgmstream/vgmstream/src/meta/wwise.c b/Frameworks/vgmstream/vgmstream/src/meta/wwise.c index f7653461b..bc946e7ff 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/wwise.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/wwise.c @@ -204,7 +204,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { switch(ww.codec) { case PCM: /* common */ /* normally riff.c has priority but it's needed when .wem is used */ - if (ww.fmt_size != 0x10 && ww.fmt_size != 0x18) goto fail; /* old, new */ + if (ww.fmt_size != 0x10 && ww.fmt_size != 0x18 && ww.fmt_size != 0x28) goto fail; /* old, new/Limbo (PC) */ if (ww.bits_per_sample != 16) goto fail; vgmstream->coding_type = (ww.big_endian ? coding_PCM16BE : coding_PCM16LE); diff --git a/Frameworks/vgmstream/vgmstream/src/meta/x360_ast.c b/Frameworks/vgmstream/vgmstream/src/meta/x360_ast.c index b3ae4cf07..89af1015d 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/x360_ast.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/x360_ast.c @@ -39,8 +39,7 @@ VGMSTREAM * init_vgmstream_x360_ast(STREAMFILE *streamFile) { { /* manually find sample offsets (XMA1 nonsense again) */ - ms_sample_data msd; - memset(&msd,0,sizeof(ms_sample_data)); + ms_sample_data msd = {0}; msd.xma_version = 1; msd.channels = channel_count; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/xma.c b/Frameworks/vgmstream/vgmstream/src/meta/xma.c index 0dfca0814..119cfb3a6 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/xma.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/xma.c @@ -68,8 +68,7 @@ VGMSTREAM * init_vgmstream_xma(STREAMFILE *streamFile) { /* fix samples; for now only XMA1 is fixed, but XMA2 num_samples don't include skip samples and xmaencode.exe doesn't use it */ if (is_xma1) { - ms_sample_data msd; - memset(&msd,0,sizeof(ms_sample_data)); + ms_sample_data msd = {0}; msd.xma_version = is_xma1 ? 1 : 2; msd.channels = channel_count; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/xvag.c b/Frameworks/vgmstream/vgmstream/src/meta/xvag.c index 382a4e0ad..313b664e6 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/xvag.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/xvag.c @@ -19,7 +19,7 @@ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) { size_t chunk_size, stream_size; /* check extension, case insensitive */ - if (!check_extensions(streamFile,"xvag")) + if (!check_extensions(streamFile,"xvag,")) goto fail; /* check header */ diff --git a/Frameworks/vgmstream/vgmstream/src/util.c b/Frameworks/vgmstream/vgmstream/src/util.c index badb2c97d..2895c62a8 100644 --- a/Frameworks/vgmstream/vgmstream/src/util.c +++ b/Frameworks/vgmstream/vgmstream/src/util.c @@ -2,16 +2,28 @@ #include "util.h" #include "streamtypes.h" -const char * filename_extension(const char * filename) { - const char * ext; +const char * filename_extension(const char * pathname) { + const char * filename; + const char * extension; - /* You know what would be nice? strrchrnul(). - * Instead I have to do it myself. */ - ext = strrchr(filename,'.'); - if (ext==NULL) ext=filename+strlen(filename); /* point to null, i.e. an empty string for the extension */ - else ext=ext+1; /* skip the dot */ + /* get basename + extension */ + filename = pathname; +#if 0 + //must detect empty extensions in folders with . in the name; not too important and DIR_SEPARATOR could improved + filename = strrchr(pathname, DIR_SEPARATOR); + if (filename == NULL) + filename = pathname; /* pathname has no separators (single filename) */ + else + filename++; /* skip the separator */ +#endif - return ext; + extension = strrchr(filename,'.'); + if (extension==NULL) + extension = filename+strlen(filename); /* point to null, i.e. an empty string for the extension */ + else + extension++; /* skip the dot */ + + return extension; } /* unused */ diff --git a/Frameworks/vgmstream/vgmstream/src/vgmstream.h b/Frameworks/vgmstream/vgmstream/src/vgmstream.h index b88373250..0803cf455 100644 --- a/Frameworks/vgmstream/vgmstream/src/vgmstream.h +++ b/Frameworks/vgmstream/vgmstream/src/vgmstream.h @@ -510,7 +510,7 @@ typedef enum { meta_PS2_MCG, /* Gunvari MCG Files (was name .GCM on disk) */ meta_ZSD, /* Dragon Booster ZSD */ meta_RedSpark, /* "RedSpark" RSD (MadWorld) */ - meta_PC_IVAUD, /* .ivaud GTA IV */ + meta_IVAUD, /* .ivaud GTA IV */ meta_NDS_HWAS, /* Spider-Man 3, Tony Hawk's Downhill Jam, possibly more... */ meta_NGC_LPS, /* Rave Master (Groove Adventure Rave)(GC) */ meta_NAOMI_ADPCM, /* NAOMI/NAOMI2 ARcade games */ @@ -686,6 +686,7 @@ typedef enum { meta_TA_AAC_VITA, /* tri-Ace AAC (Judas Code) */ meta_OGG_GWM, /* Ogg Vorbis with encryption [Metronomicon (PC)] */ meta_H4M, /* Hudson HVQM4 video [Resident Evil 0 (GC), Tales of Symphonia (GC)] */ + meta_OGG_MUS, /* Ogg Vorbis with encryption [Redux - Dark Matters (PC)] */ #ifdef VGM_USE_FFMPEG meta_FFmpeg,