diff --git a/README.md b/README.md index 0dccce26..ea127731 100644 --- a/README.md +++ b/README.md @@ -10,10 +10,10 @@ There are multiple end-user bits: - an XMPlay plugin called "xmp-vgmstream" - an Audacious plugin called "libvgmstream" -## IMPORTANT!! -### Needed files (for Windows) -Since Ogg Vorbis, MPEG audio, and other formats are now supported, you will -need to have certain DLL files.
+## Needed files (for Windows) +Since Ogg Vorbis, MPEG audio, and other external formats are supported, you +will need to have certain DLL files. + In the case of the foobar2000 component they are all bundled for convenience, or you can get them from here: https://github.com/kode54/vgmstream (also here: https://f.losno.co/vgmstream-win32-deps.zip, may not be latest). @@ -22,13 +22,13 @@ Put ```libvorbis.dll```, ```libmpg123-0.dll```, ```libg7221_decode.dll```, ```li ```at3plusdecoder.dll```, ```avcodec-vgmstream-58.dll```, ```avformat-vgmstream-58.dll```, ```avutil-vgmstream-56.dll``` and ```swresample-vgmstream-3.dll``` somewhere Windows can find them. -For Winamp/XMPlay/```test.exe``` this means in the directory with the .exe, or in a + +For Winamp/XMPlay/test.exe this means in the directory with the .exe, or in a system directory, or any other directory in the PATH variable. -### ```test.exe``` +### test.exe ``` -Usage: ./test [-o outfile.wav] [-l loop count] - [-f fade time] [-d fade delay] [-ipcmxeE] infile +Usage: test.exe [-o outfile.wav] [options] infile Options: -o outfile.wav: name of output .wav file, default is dump.wav -l loop count: loop count, default 2.0 @@ -73,8 +73,60 @@ Every file should be installed automatically by the .fb2k-component bundle. ### Audacious plugin Needs to be manually built. Instructions can be found in the source files. -### File types supported by this version of vgmstream +## Supported codec types +Quick list of codecs vgmstream supports, including many obscure ones that +are used in few games. +- PCM 16-bit +- PCM 8-bit (signed/unsigned) +- PCM 32-bit float +- u-Law/a-LAW +- CRI ADX (standard, fixed, exponential, encrypted) +- Nintendo DSP ADPCM a.k.a GC ADPCM +- Nintendo DTK ADPCM +- Nintendo AFC ADPCM +- ITU-T G.721 +- CD-ROM XA ADPCM +- Sony PSX ADPCM a.k.a VAG (badflags, bmdx, configurable) +- Sony HEVAG +- Electronic Arts EA-XA (stereo, mono, Maxis) +- Electronic Arts EA-XAS +- DVI/IMA ADPCM (stereo/mono + high/low nibble, 3DS, Omikron, SNDS, etc) +- Microsoft MS IMA ADPCM (standard, Xbox, NDS, Radical, Wwise, FSB, etc) +- Microsoft MS ADPCM +- Westwood VBR ADPCM +- Yamaha AICA ADPCM +- Procyon Studio ADPCM +- Level-5 0x555 ADPCM +- Activision EXAKT SASSC DPCM +- lsf ADPCM +- Konami MTAF ADPCM +- Konami MTA2 ADPCM +- Paradigm MC3 ADPCM +- SDX2 2:1 Squareroot-Delta-Exact compression DPCM +- CBD2 2:1 Cuberoot-Delta-Exact compression DPCM +- InterPlay ACM +- Visual Art's NWA +- CRI HCA +- Xiph Vorbis (Ogg, FSB5, Wwise, OGL, Silicon Knights) +- MPEG MP1/2/3 (standard, AHX, XVAG, FSB, AWC, P3D, etc) +- Electronic Arts EALayer3 v1 +- ITU-T G.722.1 (Polycom Siren 7) +- ITU-T G.722.1 annex C (Polycom Siren 14) +- ITU G.719 annex B (Polycom Siren 22) +- FFmpeg codecs: + - ATRAC3, ATRAC3plus + - XMA + - WMA v1, WMA v2, WMAPro + - AAC + - Bink + - AC3/SPDIF + - Opus (Ogg, Switch) + - FLAC + - Others + + +## Supported file types As manakoAT likes to say, the extension doesn't really mean anything, but it's the most obvious way to identify files. @@ -277,7 +329,7 @@ This list is not complete and many other files are supported. - .bgw (PSX configurable ADPCM) - .bnsf (G.722.1) - .caf (Apple IMA4 ADPCM, others) - - .de2 (MS ADPCM) + - .dec/de2 (MS ADPCM) - .hca (CRI High Compression Audio) - .pcm/kcey (DVI IMA ADPCM) - .lsf (LSF ADPCM) diff --git a/fb2k/foo_filetypes.h b/fb2k/foo_filetypes.h index 6e15da73..ffca17de 100644 --- a/fb2k/foo_filetypes.h +++ b/fb2k/foo_filetypes.h @@ -100,6 +100,7 @@ VGMSTREAM_DECLARE_FILE_TYPE("DBM", dbm); VGMSTREAM_DECLARE_FILE_TYPE("DCS", dcs); VGMSTREAM_DECLARE_FILE_TYPE("DDSP", ddsp); VGMSTREAM_DECLARE_FILE_TYPE("DE2", de2); +VGMSTREAM_DECLARE_FILE_TYPE("DEC", dec); VGMSTREAM_DECLARE_FILE_TYPE("DMSG", dmsg); VGMSTREAM_DECLARE_FILE_TYPE("DSP", dsp); VGMSTREAM_DECLARE_FILE_TYPE("DSPW", dspw); @@ -199,6 +200,7 @@ VGMSTREAM_DECLARE_FILE_TYPE("MWV", mwv); VGMSTREAM_DECLARE_FILE_TYPE("MxSt", mxst); VGMSTREAM_DECLARE_FILE_TYPE("MYSPD", myspd); +VGMSTREAM_DECLARE_FILE_TYPE("NAAC", naac); VGMSTREAM_DECLARE_FILE_TYPE("NDP", ndp); VGMSTREAM_DECLARE_FILE_TYPE("NGCA", ngca); VGMSTREAM_DECLARE_FILE_TYPE("NPS", nps); @@ -363,6 +365,7 @@ VGMSTREAM_DECLARE_FILE_TYPE("XWMA", xwma); VGMSTREAM_DECLARE_FILE_TYPE("XWS", xws); VGMSTREAM_DECLARE_FILE_TYPE("XWV", xwv); +VGMSTREAM_DECLARE_FILE_TYPE("V0", v0); VGMSTREAM_DECLARE_FILE_TYPE("YDSP", ydsp); VGMSTREAM_DECLARE_FILE_TYPE("YMF", ymf); diff --git a/fb2k/foo_vgmstream.cpp b/fb2k/foo_vgmstream.cpp index c6ad17d7..78ab802c 100644 --- a/fb2k/foo_vgmstream.cpp +++ b/fb2k/foo_vgmstream.cpp @@ -413,6 +413,7 @@ bool input_vgmstream::get_description_tag(pfc::string_base & temp, pfc::string_b eos = description.find_first(delimiter, pos); if (eos == pfc::infinite_size) eos = description.length(); temp.set_string(description + pos, eos - pos); + //console::formatter() << "tag=" << tag << ", delim=" << delimiter << "temp=" << temp << ", pos=" << pos << "" << eos; return true; } return false; diff --git a/src/coding/ima_decoder.c b/src/coding/ima_decoder.c index 10d45f7b..94a6b318 100644 --- a/src/coding/ima_decoder.c +++ b/src/coding/ima_decoder.c @@ -41,30 +41,8 @@ static const int IMA_IndexTable[16] = }; -/* 3DS IMA (Mario Golf, Mario Tennis; maybe other Camelot games) */ -static void n3ds_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, int nibble_shift, int32_t * hist1, int32_t * step_index) { - int sample_nibble, sample_decoded, step, delta; - - sample_nibble = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift)&0xf; - sample_decoded = *hist1; - - sample_decoded = sample_decoded << 3; - step = ADPCMTable[*step_index]; - delta = step * (sample_nibble & 7) * 2 + step; - if (sample_nibble & 8) - sample_decoded -= delta; - else - sample_decoded += delta; - sample_decoded = sample_decoded >> 3; - - *hist1 = clamp16(sample_decoded); - *step_index += IMA_IndexTable[sample_nibble]; - if (*step_index < 0) *step_index=0; - if (*step_index > 88) *step_index=88; -} - /* Standard IMA (most common) */ -static void ms_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, int nibble_shift, int32_t * hist1, int32_t * step_index) { +static void std_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, int nibble_shift, int32_t * hist1, int32_t * step_index) { int sample_nibble, sample_decoded, step, delta; sample_nibble = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift)&0xf; @@ -86,7 +64,7 @@ static void ms_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, i } /* Apple's IMA variation. Exactly the same except it uses 16b history (probably more sensitive to overflow/sign extend) */ -static void ms_ima_expand_nibble_16(VGMSTREAMCHANNEL * stream, off_t byte_offset, int nibble_shift, int16_t * hist1, int32_t * step_index) { +static void std_ima_expand_nibble_16(VGMSTREAMCHANNEL * stream, off_t byte_offset, int nibble_shift, int16_t * hist1, int32_t * step_index) { int sample_nibble, sample_decoded, step, delta; sample_nibble = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift)&0xf; @@ -107,6 +85,28 @@ static void ms_ima_expand_nibble_16(VGMSTREAMCHANNEL * stream, off_t byte_offset if (*step_index > 88) *step_index=88; } +/* 3DS IMA (Mario Golf, Mario Tennis; maybe other Camelot games) */ +static void n3ds_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, int nibble_shift, int32_t * hist1, int32_t * step_index) { + int sample_nibble, sample_decoded, step, delta; + + sample_nibble = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift)&0xf; + sample_decoded = *hist1; + + sample_decoded = sample_decoded << 3; + step = ADPCMTable[*step_index]; + delta = step * (sample_nibble & 7) * 2 + step; + if (sample_nibble & 8) + sample_decoded -= delta; + else + sample_decoded += delta; + sample_decoded = sample_decoded >> 3; + + *hist1 = clamp16(sample_decoded); + *step_index += IMA_IndexTable[sample_nibble]; + if (*step_index < 0) *step_index=0; + if (*step_index > 88) *step_index=88; +} + /* update step_index before doing current sample */ static void snds_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, int nibble_shift, int32_t * hist1, int32_t * step_index) { int sample_nibble, sample_decoded, step, delta; @@ -168,263 +168,9 @@ static void ubi_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, *hist1 = clamp16(sample_decoded); } -/* *** */ - -void decode_nds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { - int i, sample_count; - - int32_t hist1 = stream->adpcm_history1_16;//todo unneeded 16? - int step_index = stream->adpcm_step_index; - - //external interleave - - //normal header - if (first_sample == 0) { - off_t header_offset = stream->offset; - - hist1 = read_16bitLE(header_offset,stream->streamfile); - step_index = read_16bitLE(header_offset+2,stream->streamfile); - - //todo clip step_index? - } - - for (i=first_sample,sample_count=0; ioffset + 4 + i/2; - int nibble_shift = (i&1?4:0); //low nibble first - - ms_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); - outbuf[sample_count] = (short)(hist1); - } - - stream->adpcm_history1_16 = hist1; - stream->adpcm_step_index = step_index; -} - -void decode_dat4_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { - int i, sample_count; - - int32_t hist1 = stream->adpcm_history1_16;//todo unneeded 16? - int step_index = stream->adpcm_step_index; - - //external interleave - - //normal header - if (first_sample == 0) { - off_t header_offset = stream->offset; - - hist1 = read_16bitLE(header_offset,stream->streamfile); - step_index = read_8bit(header_offset+2,stream->streamfile); - - //todo clip step_index? - } - - for (i=first_sample,sample_count=0; ioffset + 4 + i/2; - int nibble_shift = (i&1?0:4); //high nibble first - - ms_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); - outbuf[sample_count] = (short)(hist1); - } - - stream->adpcm_history1_16 = hist1; - stream->adpcm_step_index = step_index; -} - -void decode_ms_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) { - int i, sample_count; - - int32_t hist1 = stream->adpcm_history1_32; - int step_index = stream->adpcm_step_index; - - //internal interleave (configurable size), mixed channels (4 byte per ch) - int block_samples = (vgmstream->interleave_block_size - 4*vgmstream->channels) * 2 / vgmstream->channels; - first_sample = first_sample % block_samples; - - //normal header (per channel) - if (first_sample == 0) { - off_t header_offset = stream->offset + 4*channel; - - hist1 = read_16bitLE(header_offset,stream->streamfile); - step_index = read_8bit(header_offset+2,stream->streamfile); - if (step_index < 0) step_index=0; - if (step_index > 88) step_index=88; - } - - for (i=first_sample,sample_count=0; ioffset + 4*channel + 4*vgmstream->channels + i/8*4*vgmstream->channels + (i%8)/2; - int nibble_shift = (i&1?4:0); //low nibble first - - ms_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); - outbuf[sample_count] = (short)(hist1); - } - - //internal interleave: increment offset on complete frame - if (i == block_samples) stream->offset += vgmstream->interleave_block_size; - - stream->adpcm_history1_32 = hist1; - stream->adpcm_step_index = step_index; -} - -void decode_rad_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) { - int i, sample_count; - - int32_t hist1 = stream->adpcm_history1_32; - int step_index = stream->adpcm_step_index; - - //internal interleave (configurable size), mixed channels (4 byte per ch) - int block_samples = (vgmstream->interleave_block_size - 4*vgmstream->channels) * 2 / vgmstream->channels; - first_sample = first_sample % block_samples; - - //inverted header (per channel) - if (first_sample == 0) { - off_t header_offset = stream->offset + 4*channel; - - step_index = read_16bitLE(header_offset,stream->streamfile); - hist1 = read_16bitLE(header_offset+2,stream->streamfile); - if (step_index < 0) step_index=0; - if (step_index > 88) step_index=88; - } - - for (i=first_sample,sample_count=0; ioffset + 4*vgmstream->channels + channel + i/2*vgmstream->channels; - int nibble_shift = (i&1?4:0); //low nibble first - - ms_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); - outbuf[sample_count] = (short)(hist1); - } - - //internal interleave: increment offset on complete frame - if (i == block_samples) stream->offset += vgmstream->interleave_block_size; - - stream->adpcm_history1_32 = hist1; - stream->adpcm_step_index = step_index; -} - -void decode_rad_ima_mono(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { - int i, sample_count; - - int32_t hist1 = stream->adpcm_history1_32; - int step_index = stream->adpcm_step_index; - - //semi-external interleave? - int block_samples = 0x14 * 2; - first_sample = first_sample % block_samples; - - //inverted header - if (first_sample == 0) { - off_t header_offset = stream->offset; - - step_index = read_16bitLE(header_offset,stream->streamfile); - hist1 = read_16bitLE(header_offset+2,stream->streamfile); - if (step_index < 0) step_index=0; - if (step_index > 88) step_index=88; - } - - for (i=first_sample,sample_count=0; ioffset + 4 + i/2; - int nibble_shift = (i&1?4:0); //low nibble first - - ms_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); - outbuf[sample_count] = (short)(hist1); - } - - stream->adpcm_history1_32 = hist1; - stream->adpcm_step_index = step_index; -} - -/* For multichannel the internal layout is (I think) mixed stereo channels (ex. 6ch: 2ch + 2ch + 2ch) */ -void decode_xbox_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) { - int i, sample_count; - - int32_t hist1 = stream->adpcm_history1_32; - int step_index = stream->adpcm_step_index; - - off_t offset = stream->offset; - - //internal interleave (0x20+4 size), mixed channels (4 byte per ch, mixed stereo) - int block_samples = (vgmstream->channels==1) ? - 32 : - 32*(vgmstream->channels&2);//todo this can be zero in 4/5/8ch = SEGFAULT using % below - first_sample = first_sample % block_samples; - - //normal header (per channel) - if (first_sample == 0) { - off_t header_offset; - header_offset = stream->offset + 4*(channel%2); - - hist1 = read_16bitLE(header_offset,stream->streamfile); - step_index = read_16bitLE(header_offset+2,stream->streamfile); - if (step_index < 0) step_index=0; - if (step_index > 88) step_index=88; - } - - for (i=first_sample,sample_count=0; ioffset + 4*(channel%2) + 4 + i/8*4 + (i%8)/2 : - stream->offset + 4*(channel%2) + 4*2 + i/8*4*2 + (i%8)/2; - nibble_shift = (i&1?4:0); //low nibble first - - ms_ima_expand_nibble(stream, offset,nibble_shift, &hist1, &step_index); - outbuf[sample_count] = (short)(hist1); - } - - //internal interleave: increment offset on complete frame - if (channelspacing==1) { - if(offset-stream->offset==32+3) // ?? - stream->offset+=36; - } else { - if(offset-stream->offset==64+(4*(channel%2))+3) // ?? - stream->offset+=36*channelspacing; - } - - stream->adpcm_history1_32 = hist1; - stream->adpcm_step_index = step_index; -} - -/* mono XBOX ADPCM for interleave */ -void decode_xbox_ima_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) { - int i, sample_count = 0, num_frame; - int32_t hist1 = stream->adpcm_history1_32; - int step_index = stream->adpcm_step_index; - - //external interleave - int block_samples = (0x24 - 0x4) * 2; /* block size - header, 2 samples per byte */ - num_frame = first_sample / block_samples; - first_sample = first_sample % block_samples; - - //normal header - if (first_sample == 0) { - off_t header_offset = stream->offset + 0x24*num_frame; - - hist1 = read_16bitLE(header_offset,stream->streamfile); - step_index = read_8bit(header_offset+2,stream->streamfile); - if (step_index < 0) step_index=0; - if (step_index > 88) step_index=88; - - //must write history from header as last nibble/sample in block is almost always 0 / not encoded - outbuf[sample_count] = (short)(hist1); - sample_count += channelspacing; - first_sample += 1; - samples_to_do -= 1; - } - - for (i=first_sample; i < first_sample + samples_to_do; i++) { /* first_sample + samples_to_do should be block_samples at most */ - off_t byte_offset = (stream->offset + 0x24*num_frame + 0x4) + (i-1)/2; - int nibble_shift = ((i-1)&1?4:0); //low nibble first - - //last nibble/sample in block is ignored (next header sample contains it) - if (i < block_samples) { - ms_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); - outbuf[sample_count] = (short)(hist1); - sample_count += channelspacing; - } - } - - stream->adpcm_history1_32 = hist1; - stream->adpcm_step_index = step_index; -} +/* ************************************ */ +/* DVI/IMA */ +/* ************************************ */ /* Standard DVI/IMA ADPCM (as in, ADPCM recommended by the IMA using Intel/DVI's implementation). * Configurable: stereo or mono/interleave nibbles, and high or low nibble first. @@ -450,7 +196,7 @@ void decode_standard_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channel is_stereo ? (!(channel&1) ? 4:0) : (!(i&1) ? 4:0) : /* even = high, odd = low */ is_stereo ? (!(channel&1) ? 0:4) : (!(i&1) ? 0:4); /* even = low, odd = high */ - ms_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); + std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); outbuf[sample_count] = (short)(hist1); } @@ -480,38 +226,6 @@ void decode_3ds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci stream->adpcm_step_index = step_index; } -void decode_apple_ima4(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { - int i, sample_count, num_frame; - int16_t hist1 = stream->adpcm_history1_16;//todo unneeded 16? - int step_index = stream->adpcm_step_index; - - //external interleave - int block_samples = (0x22 - 0x2) * 2; - num_frame = first_sample / block_samples; - first_sample = first_sample % block_samples; - - //2-byte header - if (first_sample == 0) { - off_t header_offset = stream->offset + 0x22*num_frame; - - hist1 = (int16_t)((uint16_t)read_16bitBE(header_offset,stream->streamfile) & 0xff80); - step_index = read_8bit(header_offset+1,stream->streamfile) & 0x7f; - if (step_index < 0) step_index=0; - if (step_index > 88) step_index=88; - } - - for (i=first_sample,sample_count=0; ioffset + 0x22*num_frame + 0x2) + i/2; - int nibble_shift = (i&1?4:0); //low nibble first - - ms_ima_expand_nibble_16(stream, byte_offset,nibble_shift, &hist1, &step_index); - outbuf[sample_count] = (short)(hist1); - } - - stream->adpcm_history1_16 = hist1; - stream->adpcm_step_index = step_index; -} - void decode_snds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) { int i, sample_count; @@ -558,6 +272,300 @@ void decode_otns_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * stream->adpcm_step_index = step_index; } +/* ************************************ */ +/* MS IMA */ +/* ************************************ */ + +/* IMA with frames with header and custom sizes */ +void decode_ms_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) { + int i, sample_count; + + int32_t hist1 = stream->adpcm_history1_32; + int step_index = stream->adpcm_step_index; + + //internal interleave (configurable size), mixed channels (4 byte per ch) + int block_samples = (vgmstream->interleave_block_size - 4*vgmstream->channels) * 2 / vgmstream->channels; + first_sample = first_sample % block_samples; + + //normal header (per channel) + if (first_sample == 0) { + off_t header_offset = stream->offset + 4*channel; + + hist1 = read_16bitLE(header_offset,stream->streamfile); + step_index = read_8bit(header_offset+2,stream->streamfile); + if (step_index < 0) step_index=0; + if (step_index > 88) step_index=88; + } + + for (i=first_sample,sample_count=0; ioffset + 4*channel + 4*vgmstream->channels + i/8*4*vgmstream->channels + (i%8)/2; + int nibble_shift = (i&1?4:0); //low nibble first + + std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); + outbuf[sample_count] = (short)(hist1); + } + + //internal interleave: increment offset on complete frame + if (i == block_samples) stream->offset += vgmstream->interleave_block_size; + + stream->adpcm_history1_32 = hist1; + stream->adpcm_step_index = step_index; +} + +/* MS IMA with fixed frame size and custom multichannel nibble layout. + * For multichannel the layout is (I think) mixed stereo channels (ex. 6ch: 2ch + 2ch + 2ch) */ +void decode_xbox_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) { + int i, sample_count; + + int32_t hist1 = stream->adpcm_history1_32; + int step_index = stream->adpcm_step_index; + + off_t offset = stream->offset; + + //internal interleave (0x20+4 size), mixed channels (4 byte per ch, mixed stereo) + int block_samples = (vgmstream->channels==1) ? + 32 : + 32*(vgmstream->channels&2);//todo this can be zero in 4/5/8ch = SEGFAULT using % below + first_sample = first_sample % block_samples; + + //normal header (per channel) + if (first_sample == 0) { + off_t header_offset; + header_offset = stream->offset + 4*(channel%2); + + hist1 = read_16bitLE(header_offset,stream->streamfile); + step_index = read_16bitLE(header_offset+2,stream->streamfile); + if (step_index < 0) step_index=0; + if (step_index > 88) step_index=88; + } + + for (i=first_sample,sample_count=0; ioffset + 4*(channel%2) + 4 + i/8*4 + (i%8)/2 : + stream->offset + 4*(channel%2) + 4*2 + i/8*4*2 + (i%8)/2; + nibble_shift = (i&1?4:0); //low nibble first + + std_ima_expand_nibble(stream, offset,nibble_shift, &hist1, &step_index); + outbuf[sample_count] = (short)(hist1); + } + + //internal interleave: increment offset on complete frame + if (channelspacing==1) { + if(offset-stream->offset==32+3) // ?? + stream->offset+=36; + } else { + if(offset-stream->offset==64+(4*(channel%2))+3) // ?? + stream->offset+=36*channelspacing; + } + + stream->adpcm_history1_32 = hist1; + stream->adpcm_step_index = step_index; +} + +/* mono XBOX ADPCM for interleave */ +void decode_xbox_ima_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) { + int i, sample_count = 0, num_frame; + int32_t hist1 = stream->adpcm_history1_32; + int step_index = stream->adpcm_step_index; + + //external interleave + int block_samples = (0x24 - 0x4) * 2; /* block size - header, 2 samples per byte */ + num_frame = first_sample / block_samples; + first_sample = first_sample % block_samples; + + //normal header + if (first_sample == 0) { + off_t header_offset = stream->offset + 0x24*num_frame; + + hist1 = read_16bitLE(header_offset,stream->streamfile); + step_index = read_8bit(header_offset+2,stream->streamfile); + if (step_index < 0) step_index=0; + if (step_index > 88) step_index=88; + + //must write history from header as last nibble/sample in block is almost always 0 / not encoded + outbuf[sample_count] = (short)(hist1); + sample_count += channelspacing; + first_sample += 1; + samples_to_do -= 1; + } + + for (i=first_sample; i < first_sample + samples_to_do; i++) { /* first_sample + samples_to_do should be block_samples at most */ + off_t byte_offset = (stream->offset + 0x24*num_frame + 0x4) + (i-1)/2; + int nibble_shift = ((i-1)&1?4:0); //low nibble first + + //last nibble/sample in block is ignored (next header sample contains it) + if (i < block_samples) { + std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); + outbuf[sample_count] = (short)(hist1); + sample_count += channelspacing; + } + } + + stream->adpcm_history1_32 = hist1; + stream->adpcm_step_index = step_index; +} + +void decode_nds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { + int i, sample_count; + + int32_t hist1 = stream->adpcm_history1_16;//todo unneeded 16? + int step_index = stream->adpcm_step_index; + + //external interleave + + //normal header + if (first_sample == 0) { + off_t header_offset = stream->offset; + + hist1 = read_16bitLE(header_offset,stream->streamfile); + step_index = read_16bitLE(header_offset+2,stream->streamfile); + + //todo clip step_index? + } + + for (i=first_sample,sample_count=0; ioffset + 4 + i/2; + int nibble_shift = (i&1?4:0); //low nibble first + + std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); + outbuf[sample_count] = (short)(hist1); + } + + stream->adpcm_history1_16 = hist1; + stream->adpcm_step_index = step_index; +} + +void decode_dat4_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { + int i, sample_count; + + int32_t hist1 = stream->adpcm_history1_16;//todo unneeded 16? + int step_index = stream->adpcm_step_index; + + //external interleave + + //normal header + if (first_sample == 0) { + off_t header_offset = stream->offset; + + hist1 = read_16bitLE(header_offset,stream->streamfile); + step_index = read_8bit(header_offset+2,stream->streamfile); + + //todo clip step_index? + } + + for (i=first_sample,sample_count=0; ioffset + 4 + i/2; + int nibble_shift = (i&1?0:4); //high nibble first + + std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); + outbuf[sample_count] = (short)(hist1); + } + + stream->adpcm_history1_16 = hist1; + stream->adpcm_step_index = step_index; +} + +void decode_rad_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) { + int i, sample_count; + + int32_t hist1 = stream->adpcm_history1_32; + int step_index = stream->adpcm_step_index; + + //internal interleave (configurable size), mixed channels (4 byte per ch) + int block_samples = (vgmstream->interleave_block_size - 4*vgmstream->channels) * 2 / vgmstream->channels; + first_sample = first_sample % block_samples; + + //inverted header (per channel) + if (first_sample == 0) { + off_t header_offset = stream->offset + 4*channel; + + step_index = read_16bitLE(header_offset,stream->streamfile); + hist1 = read_16bitLE(header_offset+2,stream->streamfile); + if (step_index < 0) step_index=0; + if (step_index > 88) step_index=88; + } + + for (i=first_sample,sample_count=0; ioffset + 4*vgmstream->channels + channel + i/2*vgmstream->channels; + int nibble_shift = (i&1?4:0); //low nibble first + + std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); + outbuf[sample_count] = (short)(hist1); + } + + //internal interleave: increment offset on complete frame + if (i == block_samples) stream->offset += vgmstream->interleave_block_size; + + stream->adpcm_history1_32 = hist1; + stream->adpcm_step_index = step_index; +} + +void decode_rad_ima_mono(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { + int i, sample_count; + + int32_t hist1 = stream->adpcm_history1_32; + int step_index = stream->adpcm_step_index; + + //semi-external interleave? + int block_samples = 0x14 * 2; + first_sample = first_sample % block_samples; + + //inverted header + if (first_sample == 0) { + off_t header_offset = stream->offset; + + step_index = read_16bitLE(header_offset,stream->streamfile); + hist1 = read_16bitLE(header_offset+2,stream->streamfile); + if (step_index < 0) step_index=0; + if (step_index > 88) step_index=88; + } + + for (i=first_sample,sample_count=0; ioffset + 4 + i/2; + int nibble_shift = (i&1?4:0); //low nibble first + + std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); + outbuf[sample_count] = (short)(hist1); + } + + stream->adpcm_history1_32 = hist1; + stream->adpcm_step_index = step_index; +} + +void decode_apple_ima4(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { + int i, sample_count, num_frame; + int16_t hist1 = stream->adpcm_history1_16;//todo unneeded 16? + int step_index = stream->adpcm_step_index; + + //external interleave + int block_samples = (0x22 - 0x2) * 2; + num_frame = first_sample / block_samples; + first_sample = first_sample % block_samples; + + //2-byte header + if (first_sample == 0) { + off_t header_offset = stream->offset + 0x22*num_frame; + + hist1 = (int16_t)((uint16_t)read_16bitBE(header_offset,stream->streamfile) & 0xff80); + step_index = read_8bit(header_offset+1,stream->streamfile) & 0x7f; + if (step_index < 0) step_index=0; + if (step_index > 88) step_index=88; + } + + for (i=first_sample,sample_count=0; ioffset + 0x22*num_frame + 0x2) + i/2; + int nibble_shift = (i&1?4:0); //low nibble first + + std_ima_expand_nibble_16(stream, byte_offset,nibble_shift, &hist1, &step_index); + outbuf[sample_count] = (short)(hist1); + } + + stream->adpcm_history1_16 = hist1; + stream->adpcm_step_index = step_index; +} + void decode_fsb_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) { int i, sample_count; @@ -583,7 +591,7 @@ void decode_fsb_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * o off_t byte_offset = stream->offset + 4*vgmstream->channels + 2*channel + i/4*2*vgmstream->channels + (i%4)/2;//2-byte per channel int nibble_shift = (i&1?4:0); //low nibble first - ms_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); + std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); outbuf[sample_count] = (short)(hist1); } @@ -628,7 +636,7 @@ void decode_wwise_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * //last nibble/sample in block is ignored (next header sample contains it) if (i < block_samples) { - ms_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); + std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); outbuf[sample_count] = (short)(hist1); sample_count+=channelspacing; //todo atenuation: apparently from hcs's analysis Wwise IMA decodes nibbles slightly different, reducing dbs @@ -669,7 +677,7 @@ void decode_ref_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * ou off_t byte_offset = stream->offset + 4*vgmstream->channels + block_channel_size*channel + i/2; int nibble_shift = (i&1?4:0); //low nibble first - ms_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); + std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); outbuf[sample_count] = (short)(hist1); } @@ -704,7 +712,7 @@ void decode_awc_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci off_t byte_offset = stream->offset + 4 + i/2; int nibble_shift = (i&1?4:0); //low nibble first - ms_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); + std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); outbuf[sample_count] = (short)(hist1); } diff --git a/src/coding/mpeg_decoder.c b/src/coding/mpeg_decoder.c index c08145d3..b0bf45a8 100644 --- a/src/coding/mpeg_decoder.c +++ b/src/coding/mpeg_decoder.c @@ -238,7 +238,7 @@ static void decode_mpeg_standard(VGMSTREAMCHANNEL *stream, mpeg_codec_data * dat /* end of stream, fill rest with 0s */ if (!data->bytes_in_buffer) { - memset(outbuf + samples_done * channels, 0, (samples_to_do - samples_done) * sizeof(sample)); + memset(outbuf + samples_done * channels, 0, (samples_to_do - samples_done) * channels * sizeof(sample)); break; } diff --git a/src/coding/vorbis_custom_decoder.c b/src/coding/vorbis_custom_decoder.c index 1fd256f2..ee25bb11 100644 --- a/src/coding/vorbis_custom_decoder.c +++ b/src/coding/vorbis_custom_decoder.c @@ -164,7 +164,7 @@ void decode_vorbis_custom(VGMSTREAM * vgmstream, sample * outbuf, int32_t sample decode_fail: /* on error just put some 0 samples */ - memset(outbuf + samples_done * channels, 0, (samples_to_do - samples_done) * sizeof(sample)); + memset(outbuf + samples_done * channels, 0, (samples_to_do - samples_done) * channels * sizeof(sample)); } /* converts from internal Vorbis format to standard PCM (mostly from Xiph's decoder_example.c) */ diff --git a/src/formats.c b/src/formats.c index 3a9822e9..cf77b8ce 100644 --- a/src/formats.c +++ b/src/formats.c @@ -93,6 +93,7 @@ static const char* extension_list[] = { "dcs", "ddsp", "de2", + "dec", "dmsg", "dsp", "dspw", @@ -192,6 +193,7 @@ static const char* extension_list[] = { "mxst", "myspd", + "naac", "ndp", "ngca", "nps", @@ -265,7 +267,7 @@ static const char* extension_list[] = { "sl3", "sli", "smp", - "smpl", + "smpl", //fake extension (to be removed) "snd", "snds", "sng", @@ -307,6 +309,8 @@ static const char* extension_list[] = { "ulw", "um3", + "v0", + //"v1", //dual channel with v0 "vag", "vas", "vawx", @@ -517,7 +521,7 @@ static const layout_info layout_info_list[] = { {layout_ast_blocked, "AST blocked"}, {layout_halpst_blocked, "HALPST blocked"}, {layout_xa_blocked, "CD-ROM XA"}, - {layout_ea_blocked, "blocked (EA SCHl)"}, + {layout_blocked_ea_schl, "blocked (EA SCHl)"}, {layout_blocked_ea_1snh, "blocked (EA 1SNh)"}, {layout_caf_blocked, "CAF blocked"}, {layout_wsi_blocked, ".wsi blocked"}, @@ -525,7 +529,7 @@ static const layout_info layout_info_list[] = { {layout_str_snds_blocked, ".str SNDS blocked"}, {layout_ws_aud_blocked, "Westwood Studios .aud blocked"}, {layout_matx_blocked, "Matrix .matx blocked"}, - {layout_de2_blocked, "de2 blocked"}, + {layout_blocked_dec, "blocked (DEC)"}, {layout_vs_blocked, "vs blocked"}, {layout_emff_ps2_blocked, "EMFF (PS2) blocked"}, {layout_emff_ngc_blocked, "EMFF (NGC/WII) blocked"}, @@ -535,7 +539,7 @@ static const layout_info layout_info_list[] = { {layout_psx_mgav_blocked, "MGAV blocked"}, {layout_ps2_adm_blocked, "ADM blocked"}, {layout_dsp_bdsp_blocked, "DSP blocked"}, - {layout_ivaud_blocked, "GTA IV blocked"}, + {layout_blocked_ivaud, "blocked (IVAUD)"}, {layout_ps2_iab_blocked, "IAB blocked"}, {layout_ps2_strlr_blocked, "The Bouncer STR blocked"}, {layout_rws_blocked, "RWS blocked"}, @@ -546,7 +550,7 @@ static const layout_info layout_info_list[] = { {layout_aix, "AIX interleave, internally 18-byte interleaved"}, {layout_aax, "AAX blocked, 18-byte interleaved"}, {layout_scd_int, "SCD multistream interleave"}, - {layout_ea_sns_blocked, "Electronic Arts SNS blocked"}, + {layout_blocked_ea_sns, "blocked (EA SNS)"}, {layout_blocked_awc, "blocked (AWC)"}, {layout_blocked_vgs, "blocked (VGS)"}, #ifdef VGM_USE_VORBIS @@ -568,8 +572,8 @@ static const meta_info meta_info_list[] = { {meta_UTF_DSP, "CRI ADPCM_WII header"}, {meta_DSP_AGSC, "Retro Studios AGSC header"}, {meta_DSP_CSMP, "Retro Studios CSMP header"}, - {meta_NGC_ADPDTK, "assumed Nintendo ADP by .adp extension and valid first frame"}, - {meta_RSF, "assumed Retro Studios RSF by .rsf extension and valid first bytes"}, + {meta_NGC_ADPDTK, "Nintendo ADP raw header"}, + {meta_RSF, "Retro Studios RSF raw header"}, {meta_AFC, "Nintendo AFC header"}, {meta_AST, "Nintendo AST header"}, {meta_HALPST, "HAL Laboratory HALPST header"}, @@ -681,7 +685,7 @@ static const meta_info meta_info_list[] = { {meta_XBOX_WVS, "Metal Arms WVS Header (XBOX)"}, {meta_NGC_WVS, "Metal Arms WVS Header (GameCube)"}, {meta_XBOX_MATX, "assumed Matrix file by .matx extension"}, - {meta_DE2, "gurumin .de2 with embedded funky RIFF"}, + {meta_DEC, "Falcom DEC RIFF header"}, {meta_VS, "Men in Black VS Header"}, {meta_DC_STR, "Sega Stream Asset Builder header"}, {meta_DC_STR_V2, "variant of Sega Stream Asset Builder header"}, @@ -689,6 +693,7 @@ static const meta_info meta_info_list[] = { {meta_XBOX_XVAS, "assumed TMNT file by .xvas extension"}, {meta_PS2_XA2, "Acclaim XA2 Header"}, {meta_DC_IDVI, "Capcom IDVI header"}, + {meta_KRAW, "Geometry Wars: Galaxies KRAW header"}, {meta_NGC_YMF, "YMF DSP Header"}, {meta_PS2_CCC, "CCC Header"}, {meta_PSX_FAG, "FAG Header"}, @@ -796,12 +801,12 @@ static const meta_info meta_info_list[] = { {meta_S14, "Namco .S14 raw header"}, {meta_SSS, "Namco .SSS raw header"}, {meta_PS2_GCM, "GCM 'MCG' Header"}, - {meta_PS2_SMPL, "Homura 'SMPL' Header"}, + {meta_PS2_SMPL, "Homura SMPL header"}, {meta_PS2_MSA, "Psyvariar -Complete Edition- MSA header"}, {meta_PC_SMP, "Ghostbusters .smp Header"}, {meta_NGC_PDT, "PDT DSP header"}, {meta_NGC_BO2, "Blood Omen 2 DSP header"}, - {meta_P3D, "Radical P3D Header"}, + {meta_P3D, "Radical P3D header"}, {meta_PS2_TK1, "Tekken TK5STRM1 Header"}, {meta_PS2_ADSC, "ADSC Header"}, {meta_NGC_DSP_MPDS, "MPDS DSP header"}, @@ -900,6 +905,7 @@ static const meta_info meta_info_list[] = { {meta_PC_AL2, "Illwinter Game Design AL2 raw header"}, {meta_PC_AST, "Capcom AST (PC) header"}, {meta_UBI_SB, "Ubisoft SBx header"}, + {meta_NAAC, "Namco NAAC header"}, #ifdef VGM_USE_VORBIS {meta_OGG_VORBIS, "Ogg Vorbis"}, diff --git a/src/layout/blocked.c b/src/layout/blocked.c index e0e73b76..e9e0793d 100644 --- a/src/layout/blocked.c +++ b/src/layout/blocked.c @@ -80,8 +80,8 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * case layout_xa_blocked: xa_block_update(vgmstream->next_block_offset,vgmstream); break; - case layout_ea_blocked: - ea_schl_block_update(vgmstream->next_block_offset,vgmstream); + case layout_blocked_ea_schl: + block_update_ea_schl(vgmstream->next_block_offset,vgmstream); break; case layout_blocked_ea_1snh: block_update_ea_1snh(vgmstream->next_block_offset,vgmstream); @@ -101,8 +101,8 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * case layout_matx_blocked: matx_block_update(vgmstream->next_block_offset,vgmstream); break; - case layout_de2_blocked: - de2_block_update(vgmstream->next_block_offset,vgmstream); + case layout_blocked_dec: + block_update_dec(vgmstream->next_block_offset,vgmstream); break; case layout_emff_ps2_blocked: emff_ps2_block_update(vgmstream->next_block_offset,vgmstream); @@ -125,8 +125,8 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * case layout_filp_blocked: filp_block_update(vgmstream->next_block_offset,vgmstream); break; - case layout_ivaud_blocked: - ivaud_block_update(vgmstream->next_block_offset,vgmstream); + case layout_blocked_ivaud: + block_update_ivaud(vgmstream->next_block_offset,vgmstream); break; case layout_psx_mgav_blocked: psx_mgav_block_update(vgmstream->next_block_offset,vgmstream); @@ -152,8 +152,8 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * case layout_hwas_blocked: hwas_block_update(vgmstream->next_block_offset,vgmstream); break; - case layout_ea_sns_blocked: - ea_sns_block_update(vgmstream->next_block_offset,vgmstream); + case layout_blocked_ea_sns: + block_update_ea_sns(vgmstream->next_block_offset,vgmstream); break; case layout_blocked_awc: block_update_awc(vgmstream->next_block_offset,vgmstream); diff --git a/src/layout/blocked_dec.c b/src/layout/blocked_dec.c new file mode 100644 index 00000000..3a7809dc --- /dev/null +++ b/src/layout/blocked_dec.c @@ -0,0 +1,21 @@ +#include "layout.h" + +/* Falcom RIFF blocks (.DEC/DE2) */ +void block_update_dec(off_t block_offset, VGMSTREAM * vgmstream) { + STREAMFILE* streamFile = vgmstream->ch[0].streamfile; + size_t block_size, header_size; + int i; + + header_size = 0x08; + block_size = read_32bitLE(block_offset,streamFile); + /* 0x04: PCM size? */ + + vgmstream->current_block_offset = block_offset; + vgmstream->current_block_size = block_size; + vgmstream->next_block_offset = block_offset + block_size + header_size; + + /* MSADPCM = same offset per channel */ + for (i = 0; i < vgmstream->channels; i++) { + vgmstream->ch[i].offset = vgmstream->current_block_offset + header_size; + } +} diff --git a/src/layout/ea_block.c b/src/layout/blocked_ea_schl.c similarity index 97% rename from src/layout/ea_block.c rename to src/layout/blocked_ea_schl.c index 375889aa..dc35e087 100644 --- a/src/layout/ea_block.c +++ b/src/layout/blocked_ea_schl.c @@ -3,7 +3,7 @@ #include "../vgmstream.h" /* set up for the block at the given offset */ -void ea_schl_block_update(off_t block_offset, VGMSTREAM * vgmstream) { +void block_update_ea_schl(off_t block_offset, VGMSTREAM * vgmstream) { int i; int new_schl = 0; STREAMFILE* streamFile = vgmstream->ch[0].streamfile; diff --git a/src/layout/ea_sns_blocked.c b/src/layout/blocked_ea_sns.c similarity index 92% rename from src/layout/ea_sns_blocked.c rename to src/layout/blocked_ea_sns.c index 6e8c41e2..d74dcdc4 100644 --- a/src/layout/ea_sns_blocked.c +++ b/src/layout/blocked_ea_sns.c @@ -3,7 +3,7 @@ #include "../vgmstream.h" /* EA "SNS "blocks (most common in .SNS) */ -void ea_sns_block_update(off_t block_offset, VGMSTREAM * vgmstream) { +void block_update_ea_sns(off_t block_offset, VGMSTREAM * vgmstream) { STREAMFILE* streamFile = vgmstream->ch[0].streamfile; uint32_t block_size, block_samples; size_t file_size = get_streamfile_size(streamFile); diff --git a/src/layout/ivaud_layout.c b/src/layout/blocked_ivaud.c similarity index 92% rename from src/layout/ivaud_layout.c rename to src/layout/blocked_ivaud.c index f5df3c7b..3a950e31 100644 --- a/src/layout/ivaud_layout.c +++ b/src/layout/blocked_ivaud.c @@ -2,7 +2,7 @@ #include "../vgmstream.h" /* set up for the block at the given offset */ -void ivaud_block_update(off_t block_offset, VGMSTREAM * vgmstream) { +void block_update_ivaud(off_t block_offset, VGMSTREAM * vgmstream) { int i; off_t start_offset; off_t interleave_size; diff --git a/src/layout/de2_blocked.c b/src/layout/de2_blocked.c deleted file mode 100644 index a89ddbaf..00000000 --- a/src/layout/de2_blocked.c +++ /dev/null @@ -1,18 +0,0 @@ -#include "layout.h" -#include "../vgmstream.h" - -/* set up for the block at the given offset */ -void de2_block_update(off_t block_offset, VGMSTREAM * vgmstream) { - int i; - vgmstream->current_block_offset = block_offset; - vgmstream->current_block_size = read_32bitLE( - vgmstream->current_block_offset, - vgmstream->ch[0].streamfile); - vgmstream->next_block_offset = block_offset+8+read_32bitLE( - vgmstream->current_block_offset, - vgmstream->ch[0].streamfile); - - for (i=0;ichannels;i++) { - vgmstream->ch[i].offset = vgmstream->current_block_offset + 8; - } -} diff --git a/src/layout/layout.h b/src/layout/layout.h index d0ab95ed..bc206ea4 100644 --- a/src/layout/layout.h +++ b/src/layout/layout.h @@ -15,7 +15,7 @@ void halpst_block_update(off_t block_ofset, VGMSTREAM * vgmstream); void xa_block_update(off_t block_offset, VGMSTREAM * vgmstream); -void ea_schl_block_update(off_t block_offset, VGMSTREAM * vgmstream); +void block_update_ea_schl(off_t block_offset, VGMSTREAM * vgmstream); void block_update_ea_1snh(off_t block_offset, VGMSTREAM * vgmstream); @@ -29,7 +29,7 @@ void ws_aud_block_update(off_t block_offset, VGMSTREAM * vgmstream); void matx_block_update(off_t block_offset, VGMSTREAM * vgmstream); -void de2_block_update(off_t block_offset, VGMSTREAM * vgmstream); +void block_update_dec(off_t block_offset, VGMSTREAM * vgmstream); void vs_block_update(off_t block_offset, VGMSTREAM * vgmstream); @@ -45,7 +45,7 @@ void thp_block_update(off_t block_offset, VGMSTREAM * vgmstream); void filp_block_update(off_t block_offset, VGMSTREAM * vgmstream); -void ivaud_block_update(off_t block_offset, VGMSTREAM * vgmstream); +void block_update_ivaud(off_t block_offset, VGMSTREAM * vgmstream); void psx_mgav_block_update(off_t block_offset, VGMSTREAM * vgmstream); @@ -63,8 +63,7 @@ void rws_block_update(off_t block_offset, VGMSTREAM * vgmstream); void hwas_block_update(off_t block_offset, VGMSTREAM * vgmstream); -void ea_sns_block_update(off_t block_offset, VGMSTREAM * vgmstream); - +void block_update_ea_sns(off_t block_offset, VGMSTREAM * vgmstream); void block_update_awc(off_t block_offset, VGMSTREAM * vgmstream); void block_update_vgs(off_t block_offset, VGMSTREAM * vgmstream); diff --git a/src/libvgmstream.vcproj b/src/libvgmstream.vcproj index 0783f67b..11fc016b 100644 --- a/src/libvgmstream.vcproj +++ b/src/libvgmstream.vcproj @@ -301,7 +301,7 @@ > + + @@ -1603,15 +1607,15 @@ > - + - + @@ -259,6 +259,7 @@ + @@ -474,9 +475,9 @@ - - - + + + @@ -484,7 +485,7 @@ - + diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters index 137aeaba..935efb30 100644 --- a/src/libvgmstream.vcxproj.filters +++ b/src/libvgmstream.vcxproj.filters @@ -172,7 +172,7 @@ meta\Source Files - + meta\Source Files @@ -190,7 +190,7 @@ meta\Source Files - + meta\Source Files @@ -295,6 +295,9 @@ meta\Source Files + + meta\Source Files + meta\Source Files @@ -934,13 +937,13 @@ layout\Source Files - + layout\Source Files - + layout\Source Files - + layout\Source Files @@ -967,7 +970,7 @@ layout\Source Files - + layout\Source Files diff --git a/src/meta/aix.c b/src/meta/aix.c index 840af854..7ac2704a 100644 --- a/src/meta/aix.c +++ b/src/meta/aix.c @@ -61,7 +61,7 @@ VGMSTREAM * init_vgmstream_aix(STREAMFILE *streamFile) { goto fail; sample_rate = read_32bitBE(stream_list_offset+8,streamFile); - if (!check_sample_rate(sample_rate)) + if (sample_rate < 300 || sample_rate > 96000) goto fail; samples_in_segment = calloc(segment_count,sizeof(int32_t)); diff --git a/src/meta/Cstr.c b/src/meta/cstr.c similarity index 99% rename from src/meta/Cstr.c rename to src/meta/cstr.c index 39d5d5e0..54218e20 100644 --- a/src/meta/Cstr.c +++ b/src/meta/cstr.c @@ -3,8 +3,7 @@ #include "../util.h" /* .dsp w/ Cstr header, seen in Star Fox Assault and Donkey Konga */ - -VGMSTREAM * init_vgmstream_Cstr(STREAMFILE *streamFile) { +VGMSTREAM * init_vgmstream_cstr(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[PATH_LIMIT]; diff --git a/src/meta/de2.c b/src/meta/de2.c deleted file mode 100644 index 83f004a7..00000000 --- a/src/meta/de2.c +++ /dev/null @@ -1,101 +0,0 @@ -#include "meta.h" -#include "../layout/layout.h" -#include "../util.h" - -/* Gurumin .de2 */ -/* A ways into the file we have a fake RIFF header wrapping MS ADPCM */ - -VGMSTREAM * init_vgmstream_de2(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - - off_t riff_off; - int channel_count; - int sample_count; - int sample_rate; - off_t start_offset; - - int loop_flag = 0; - uint32_t data_size; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("de2",filename_extension(filename))) goto fail; - - /* still not sure what this is for, but consistently 0xb */ - if (read_32bitLE(0x04,streamFile)!=0xb) goto fail; - - /* legitimate! really! */ - riff_off = 0x10 + - (read_32bitLE(0x0c,streamFile) ^ read_32bitLE(0x04,streamFile)); - - /* check header */ - if ((uint32_t)read_32bitBE(riff_off+0,streamFile)!=0x52494646) /* "RIFF" */ - goto fail; - /* check for WAVE form */ - if ((uint32_t)read_32bitBE(riff_off+8,streamFile)!=0x57415645) /* "WAVE" */ - goto fail; - /* check for "fmt " */ - if ((uint32_t)read_32bitBE(riff_off+12,streamFile)!=0x666d7420) /* "fmt " */ - goto fail; - /* check for "data" */ - if ((uint32_t)read_32bitBE(riff_off+0x24,streamFile)!=0x64617461) /* "data" */ - goto fail; - /* check for bad fmt chunk size */ - if (read_32bitLE(riff_off+0x10,streamFile)!=0x12) goto fail; - - sample_rate = read_32bitLE(riff_off+0x18,streamFile); - - channel_count = read_16bitLE(riff_off+0x16,streamFile); - if (channel_count != 2) goto fail; - - /* PCM */ - if (read_16bitLE(riff_off+0x14,streamFile) != 1) goto fail; - - /* 16-bit */ - if (read_16bitLE(riff_off+0x20,streamFile) != 4 || - read_16bitLE(riff_off+0x22,streamFile) != 16) goto fail; - - start_offset = riff_off + 0x2c; - data_size = read_32bitLE(riff_off+0x28,streamFile); - - sample_count = data_size/2/channel_count; - - /* build the VGMSTREAM */ - - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - vgmstream->num_samples = sample_count; - vgmstream->sample_rate = sample_rate; - - vgmstream->coding_type = coding_MSADPCM; - vgmstream->layout_type = layout_de2_blocked; - vgmstream->interleave_block_size = 0x800; - - vgmstream->meta_type = meta_DE2; - - /* open the file, set up each channel */ - { - int i; - - vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename, - STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!vgmstream->ch[0].streamfile) goto fail; - - for (i=0;ich[i].streamfile = vgmstream->ch[0].streamfile; - } - } - - /* start me up */ - de2_block_update(start_offset,vgmstream); - - return vgmstream; - - /* clean up anything we may have opened */ -fail: - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} diff --git a/src/meta/dec.c b/src/meta/dec.c new file mode 100644 index 00000000..0d562b7a --- /dev/null +++ b/src/meta/dec.c @@ -0,0 +1,183 @@ +#include "meta.h" +#include "../layout/layout.h" + +#define TXT_LINE_MAX 0x1000 +static int get_falcom_looping(STREAMFILE *streamFile, int *out_loop_start, int *out_loop_end); + +/* .DEC/DE2 - from Falcom PC games (Xanadu Next, Zwei!!, VM Japan, Gurumin) */ +VGMSTREAM * init_vgmstream_dec(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + off_t start_offset; + off_t riff_off = 0x00; + size_t pcm_size = 0; + int loop_flag, channel_count, sample_rate, loop_start = 0, loop_end = 0; + + + /* check extension (.dec: main, .de2: Gurumin) */ + if ( !check_extensions(streamFile,"dec,de2") ) + goto fail; + + /* Gurumin has extra data, maybe related to rhythm (~0x50000) */ + if (check_extensions(streamFile,"de2")) { + /* still not sure what this is for, but consistently 0xb */ + if (read_32bitLE(0x04,streamFile) != 0xb) goto fail; + + /* legitimate! really! */ + riff_off = 0x10 + (read_32bitLE(0x0c,streamFile) ^ read_32bitLE(0x04,streamFile)); + } + + + /* fake PCM RIFF header (the original WAV's) wrapping MS-ADPCM */ + if (read_32bitBE(riff_off+0x00,streamFile) != 0x52494646 || /* "RIFF" */ + read_32bitBE(riff_off+0x08,streamFile) != 0x57415645) /* "WAVE" */ + goto fail; + + if (read_32bitBE(riff_off+0x0c,streamFile) == 0x50414420) { /* "PAD " (Zwei!!), blank with wrong chunk size */ + sample_rate = 44100; + channel_count = 2; + pcm_size = read_32bitLE(riff_off+0x04,streamFile) - 0x24; + /* somehow there is garbage at the beginning of some tracks */ + } + else if (read_32bitBE(riff_off+0x0c,streamFile) == 0x666D7420) { /* "fmt " (rest) */ + //if (read_32bitLE(riff_off+0x10,streamFile) != 0x12) goto fail; /* 0x10 in some */ + if (read_16bitLE(riff_off+0x14,streamFile) != 0x01) goto fail; /* PCM (actually MS-ADPCM) */ + if (read_16bitLE(riff_off+0x20,streamFile) != 4 || + read_16bitLE(riff_off+0x22,streamFile) != 16) goto fail; /* 16-bit */ + + channel_count = read_16bitLE(riff_off+0x16,streamFile); + sample_rate = read_32bitLE(riff_off+0x18,streamFile); + if (read_32bitBE(riff_off+0x24,streamFile) == 0x64617461) { /* "data" size except in some Zwei!! */ + pcm_size = read_32bitLE(riff_off+0x28,streamFile); + } else { + pcm_size = read_32bitLE(riff_off+0x04,streamFile) - 0x24; + } + } + else { + goto fail; + } + + if (channel_count != 2) + goto fail; + + start_offset = riff_off + 0x2c; + loop_flag = get_falcom_looping(streamFile, &loop_start, &loop_end); + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + vgmstream->sample_rate = sample_rate; + vgmstream->num_samples = pcm_size / 2 / channel_count; + vgmstream->loop_start_sample = loop_start; + vgmstream->loop_end_sample = loop_end; + + vgmstream->coding_type = coding_MSADPCM; + vgmstream->interleave_block_size = 0x800; + vgmstream->layout_type = layout_blocked_dec; + + vgmstream->meta_type = meta_DEC; + + /* open the file for reading */ + if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) + goto fail; + + block_update_dec(start_offset, vgmstream); + + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} + + +/* Falcom loves loop points in external text files, here we parse them */ +typedef enum { XANADU_NEXT, ZWEI, DINOSAUR_RESURRECTION, GURUMIN } falcom_loop_t; +static int get_falcom_looping(STREAMFILE *streamFile, int *out_loop_start, int *out_loop_end) { + STREAMFILE *streamText; + off_t txt_offset = 0x00; + falcom_loop_t type; + int loop_start = 0, loop_end = 0, loop_flag = 0; + char filename[TXT_LINE_MAX]; + + + /* try one of the many loop files */ + if ((streamText = open_stream_name(streamFile,"bgm.tbl")) != NULL) { + type = XANADU_NEXT; + } + else if ((streamText = open_stream_name(streamFile,"bgm.scr")) != NULL) { + type = ZWEI; + } + else if ((streamText = open_stream_name(streamFile,"loop.txt")) != NULL) { /* actual name in Shift JIS, 0x838B815B8376 */ + type = DINOSAUR_RESURRECTION; + } + else if ((streamText = open_stream_name(streamFile,"map.itm")) != NULL) { + type = GURUMIN; + } + else { + goto end; + } + + get_streamfile_name(streamFile,filename,TXT_LINE_MAX); + + /* read line by line */ + while (txt_offset < get_streamfile_size(streamText)) { + char line[TXT_LINE_MAX]; + char name[TXT_LINE_MAX]; + int ok, line_done, loop, bytes_read; + + bytes_read = get_streamfile_text_line(TXT_LINE_MAX,line, txt_offset,streamText, &line_done); + if (!line_done) goto end; + + txt_offset += bytes_read; + + if (line[0]=='/' || line[0]=='#' || line[0]=='[' || line[0]=='\0') /* comment/empty */ + continue; + + /* each game changes line format, wee */ + switch(type) { + case XANADU_NEXT: /* "XANA000", 0, 0,99999990,0 */ + ok = sscanf(line,"\"%[^\"]\", %*d, %d, %d, %d", name,&loop_start,&loop_end,&loop); + if (ok == 4 && strncasecmp(filename,name,strlen(name)) == 0) { + loop_flag = (loop && loop_end != 0); + goto end; + } + break; + + case ZWEI: /* 1,.\wav\bgm01.wav,497010,7386720;//comment */ + ok = sscanf(line,"%*i,.\\wav\\%[^.].dec,%d,%d;%*s", name,&loop_start,&loop_end); + if (ok == 3 && strncasecmp(filename,name,strlen(name)) == 0) { + loop_flag = (loop_end != 9000000); + goto end; + } + break; + + case DINOSAUR_RESURRECTION: /* 01 970809 - 8015852 */ + strcpy(name,"dinow_"); /* for easier comparison */ + ok = sscanf(line,"%[^ ] %d - %d", (name+6), &loop_start,&loop_end); + if (ok == 3 && strncasecmp(filename,name,strlen(name)) == 0) { + loop_flag = 1; + goto end; + } + break; + + case GURUMIN: /* 0003 BGM03 dec 00211049 02479133 00022050 00000084 //comment */ + ok = sscanf(line,"%*i %[^ \t] %*[^ \t] %d %d %*d %*d %*s", name,&loop_start,&loop_end); + if (ok == 3 && strncasecmp(filename,name,strlen(name)) == 0) { + loop_flag = (loop_end != 99999999 && loop_end != 10000000); + goto end; + } + break; + } + } + +end: + if (loop_flag) { + *out_loop_start = loop_start; + *out_loop_end = loop_end; + } + + if (streamText) close_streamfile(streamText); + return loop_flag; +} diff --git a/src/meta/ea_schl.c b/src/meta/ea_schl.c index 2d41606b..ae23cc02 100644 --- a/src/meta/ea_schl.c +++ b/src/meta/ea_schl.c @@ -250,7 +250,7 @@ static VGMSTREAM * init_vgmstream_ea_variable_header(STREAMFILE *streamFile, ea_ } } else { - vgmstream->layout_type = layout_ea_blocked; + vgmstream->layout_type = layout_blocked_ea_schl; } if (is_bnk) @@ -413,7 +413,7 @@ static VGMSTREAM * init_vgmstream_ea_variable_header(STREAMFILE *streamFile, ea_ } else { /* setup first block to update offsets */ - ea_schl_block_update(start_offset,vgmstream); + block_update_ea_schl(start_offset,vgmstream); } diff --git a/src/meta/ea_schl_fixed.c b/src/meta/ea_schl_fixed.c index 42f25c55..1b56893e 100644 --- a/src/meta/ea_schl_fixed.c +++ b/src/meta/ea_schl_fixed.c @@ -58,7 +58,7 @@ VGMSTREAM * init_vgmstream_ea_schl_fixed(STREAMFILE *streamFile) { vgmstream->meta_type = meta_EA_SCHL_fixed; - vgmstream->layout_type = layout_ea_blocked; + vgmstream->layout_type = layout_blocked_ea_schl; switch (ea.codec) { case EA_CODEC_PCM: @@ -80,7 +80,7 @@ VGMSTREAM * init_vgmstream_ea_schl_fixed(STREAMFILE *streamFile) { goto fail; /* setup first block to update offsets */ - ea_schl_block_update(start_offset,vgmstream); + block_update_ea_schl(start_offset,vgmstream); return vgmstream; diff --git a/src/meta/ea_snu.c b/src/meta/ea_snu.c index 31fd41eb..5c4708ac 100644 --- a/src/meta/ea_snu.c +++ b/src/meta/ea_snu.c @@ -6,9 +6,9 @@ /* .SNU - from EA Redwood Shores/Visceral games (Dead Space, Dante's Inferno, The Godfather 2) */ VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - int channel_count, loop_flag = 0, channel_config, codec, sample_rate, flags; + int channel_count, loop_flag = 0, version, codec, channel_config, sample_rate, flags; uint32_t num_samples, loop_start = 0, loop_end = 0; - off_t start_offset; + off_t start_offset, header_offset; int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL; @@ -16,7 +16,7 @@ VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE *streamFile) { if (!check_extensions(streamFile,"snu")) goto fail; - /* check header (the first 0x10 are BE/LE depending on platform) */ + /* EA SNU header (BE/LE depending on platform) */ /* 0x00(1): related to sample rate? (03=48000) * 0x01(1): flags/count? (when set has extra block data before start_offset) * 0x02(1): always 0? @@ -32,32 +32,48 @@ VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE *streamFile) { read_32bit = read_32bitLE; } - start_offset = read_32bit(0x08,streamFile); + header_offset = 0x10; /* points to EA SNH/SPH header */ + start_offset = read_32bit(0x08,streamFile); /* points to EA SNS/SPS blocks */ - codec = read_8bit(0x10,streamFile); - channel_config = read_8bit(0x11,streamFile); - sample_rate = (uint16_t)read_16bitBE(0x12,streamFile); - flags = (uint8_t)read_8bit(0x14,streamFile); /* upper nibble only? */ - num_samples = (uint32_t)read_32bitBE(0x14,streamFile) & 0x00FFFFFF; - /* 0x18: null?, 0x1c: null? */ - if (flags != 0x60 && flags != 0x40) { - VGM_LOG("EA SNS: unknown flag\n"); + /* Beyond is the newest EA header (from EAAudioCore library) still generated by sx.exe. + * Its audio "assets" come in separate RAM headers (.SNR/SPH) and raw blocked streams (.SNS/SPS), + * or together in pseudoformats (.SNU, .SBR+.SBS banks, .AEMS, .MUS, etc). + * Some .SNR include stream data, while most (all?) .SPS have headers so .SPH is optional. */ + + /* EA SNR header */ + version = (read_8bit(header_offset + 0x00,streamFile) >> 4) & 0xf; + codec = (read_8bit(header_offset + 0x00,streamFile) >> 0) & 0xf; + channel_config = read_8bit(header_offset + 0x01,streamFile); + sample_rate = (uint16_t)read_16bitBE(header_offset + 0x02,streamFile); + flags = (uint8_t)read_8bit(header_offset + 0x04,streamFile); /* upper nibble only? */ + num_samples = (uint32_t)read_32bitBE(header_offset + 0x04,streamFile) & 0x00FFFFFF; + /* optional, in some headers: + * 0x08: null? + * 0x0c: varies (ex. null, full size) */ + /* headered .SPS start with an id of 0x480000xx (not present in .SPH = not part of the header) */ + + /* V0: SNR+SNS, V1: SPR+SPS (not apparent differences) */ + if (version != 0 && version != 1) { + VGM_LOG("EA SNS/SPS: unknown version\n"); goto fail; } -#if 0 - //todo not working ok with blocks in XAS - //todo check if EA-XMA loops (Dante's Inferno doesn't) - if (flags & 0x60) { /* full loop, seen in ambient tracks */ + /* & 0x40: stream asset?, 0x20: full loop?, 0x00: RAM asset?, 0x01: loop? */ + if (flags != 0x60 && flags != 0x40) { + VGM_LOG("EA SNS/SPS: unknown flag 0x%02x\n", flags); + } + + /* full loop seen in Dead Space ambient tracks */ + if (flags == 0x60) { + VGM_LOG("flg=%x\n",flags); loop_flag = 1; loop_start = 0; loop_end = num_samples; } -#endif - //channel_count = (channel_config >> 2) + 1; //todo test - /* 01/02/03 = 1 ch?, 05/06/07 = 2/3 ch?, 0d/0e/0f = 4/5 ch?, 15/16/17 = 6/7 ch?, 1d/1e/1f = 8 ch? */ + /* accepted channel configs only seem to be mono/stereo/quad/5.1/7.1 */ + //channel_count = ((channel_config >> 2) & 0xf) + 1; switch(channel_config) { case 0x00: channel_count = 1; break; case 0x04: channel_count = 2; break; @@ -65,7 +81,7 @@ VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE *streamFile) { case 0x14: channel_count = 6; break; case 0x1c: channel_count = 8; break; default: - VGM_LOG("EA SNU: unknown channel config 0x%02x\n", channel_config); + VGM_LOG("EA SNS/SPS: unknown channel config 0x%02x\n", channel_config); goto fail; } @@ -81,15 +97,16 @@ VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE *streamFile) { vgmstream->meta_type = meta_EA_SNU; + /* EA decoder list and known internal FourCCs */ switch(codec) { case 0x04: /* "Xas1": EA-XAS (Dead Space PC/PS3) */ vgmstream->coding_type = coding_EA_XAS; - vgmstream->layout_type = layout_ea_sns_blocked; + vgmstream->layout_type = layout_blocked_ea_sns; break; #if 0 #ifdef VGM_USE_MPEG - case 0x07: { /* "EL32S": EALayer3 v2 "S" (Dante's Inferno PS3) */ + case 0x07: { /* "L32S": EALayer3 v2 "S" (Dante's Inferno PS3) */ mpeg_custom_config cfg; off_t mpeg_start_offset = start_offset + 0x08; @@ -99,7 +116,7 @@ VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE *streamFile) { vgmstream->codec_data = init_mpeg_custom_codec_data(streamFile, mpeg_start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_EAL32S, &cfg); if (!vgmstream->codec_data) goto fail; - vgmstream->layout_type = layout_ea_sns_blocked; + vgmstream->layout_type = layout_blocked_ea_sns; break; } #endif @@ -133,19 +150,23 @@ VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE *streamFile) { break; } #endif - case 0x00: /* "NONE" */ - case 0x01: /* not used? */ - case 0x02: /* "P6B0": PCM16BE */ + case 0x00: /* "NONE" (internal codec not set flag) */ + case 0x01: /* not used/reserved? MP30/P6L0/P2B0/P2L0/P8S0/P8U0/PFN0? */ + case 0x02: /* "P6B0": PCM16BE */ case 0x05: /* "EL31": EALayer3 v1 b (with PCM blocks in normal EA-frames?) */ - case 0x06: /* "EL32P": EALayer3 v2 "P" */ - case 0x09: /* EASpeex? */ - case 0x0c: /* EAOpus? */ - case 0x0e: /* XAS variant? */ - case 0x0f: /* EALayer3 variant? */ - /* also 0x1n variations, used in other headers */ + case 0x06: /* "L32P": EALayer3 v2 "P" */ + + case 0x08: /* ? */ + case 0x09: /* EASpeex? "Esp0" (libspeex variant) */ + case 0x0a: /* EATrax (ATRAC9 variant, deflated frames) */ + case 0x0b: /* ? */ + case 0x0c: /* EAOpus (inside each SNS/SPS block is 16b frame size + Opus standard? packet) */ + case 0x0d: /* ? */ + case 0x0e: /* ? */ + case 0x0f: /* ? */ default: - VGM_LOG("EA SNU: unknown codec 0x%02x\n", codec); + VGM_LOG("EA SNS/SPS: unknown codec 0x%02x\n", codec); goto fail; } @@ -154,8 +175,8 @@ VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE *streamFile) { if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) goto fail; - if (vgmstream->layout_type == layout_ea_sns_blocked) - ea_sns_block_update(start_offset, vgmstream); + if (vgmstream->layout_type == layout_blocked_ea_sns) + block_update_ea_sns(start_offset, vgmstream); return vgmstream; diff --git a/src/meta/genh.c b/src/meta/genh.c index b4a7e36b..787ba868 100644 --- a/src/meta/genh.c +++ b/src/meta/genh.c @@ -220,13 +220,13 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) { for (i=0;ichannels;i++) { int16_t (*read_16bit)(off_t , STREAMFILE*) = genh.coef_big_endian ? read_16bitBE : read_16bitLE; - /* normal/split coefs */ - if ((genh.coef_type & 1) == 0) { /* bit 0 - split coefs (2 arrays) */ + /* normal/split coefs bit flag */ + if ((genh.coef_type & 1) == 0) { /* not set: normal coefs, all 16 interleaved into one array */ for (j=0;j<16;j++) { vgmstream->ch[i].adpcm_coef[j] = read_16bit(genh.coef[i]+j*2,streamFile); } } - else { + else { /* set: split coefs, 8 coefs in the main array, additional offset to 2nd array given at 0x34 for left, 0x38 for right */ for (j=0;j<8;j++) { vgmstream->ch[i].adpcm_coef[j*2]=read_16bit(genh.coef[i]+j*2,streamFile); vgmstream->ch[i].adpcm_coef[j*2+1]=read_16bit(genh.coef_splitted[i]+j*2,streamFile); @@ -353,8 +353,8 @@ static int parse_genh(STREAMFILE * streamFile, genh_header * genh) { genh->coef_interleave_type = read_32bitLE(0x2C,streamFile); /* DSP coefficient variants */ - /* bit 0 - split coefs (2 arrays) */ - /* bit 1 - little endian coefs */ + /* bit 0 flag - split coefs (2 arrays) */ + /* bit 1 flag - little endian coefs (for some 3DS) */ genh->coef_type = read_32bitLE(0x30,streamFile); genh->coef_big_endian = ((genh->coef_type & 2) == 0); diff --git a/src/meta/ivaud.c b/src/meta/ivaud.c index 0d585207..5584dc31 100644 --- a/src/meta/ivaud.c +++ b/src/meta/ivaud.c @@ -38,7 +38,7 @@ VGMSTREAM * init_vgmstream_ivaud(STREAMFILE *streamFile) { vgmstream->sample_rate = read_32bitLE(block_table_offset + 0x04,streamFile); vgmstream->coding_type = coding_IMA_int; - vgmstream->layout_type = layout_ivaud_blocked; + vgmstream->layout_type = layout_blocked_ivaud; vgmstream->meta_type = meta_PC_IVAUD; /* open the file for reading */ @@ -57,7 +57,7 @@ VGMSTREAM * init_vgmstream_ivaud(STREAMFILE *streamFile) { // to avoid troubles with "extra" samples vgmstream->num_samples=((read_32bitLE(0x60,streamFile)/2)*2); - ivaud_block_update(start_offset,vgmstream); + block_update_ivaud(start_offset,vgmstream); return vgmstream; diff --git a/src/meta/meta.h b/src/meta/meta.h index fcb64f80..13d504e4 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -15,7 +15,7 @@ VGMSTREAM * init_vgmstream_ast(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_brstm(STREAMFILE *streamFile); -VGMSTREAM * init_vgmstream_Cstr(STREAMFILE *streamFile); +VGMSTREAM * init_vgmstream_cstr(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_gcsw(STREAMFILE *streamFile); @@ -252,7 +252,7 @@ VGMSTREAM * init_vgmstream_dc_str_v2(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_xbox_matx(STREAMFILE *streamFile); -VGMSTREAM * init_vgmstream_de2(STREAMFILE *streamFile); +VGMSTREAM * init_vgmstream_dec(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_vs(STREAMFILE *streamFile); @@ -687,6 +687,8 @@ VGMSTREAM * init_vgmstream_pc_al2(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_pc_ast(STREAMFILE * streamFile); +VGMSTREAM * init_vgmstream_naac(STREAMFILE * streamFile); + VGMSTREAM * init_vgmstream_ubi_sb(STREAMFILE * streamFile); #endif /*_META_H*/ diff --git a/src/meta/mus_acm.c b/src/meta/mus_acm.c index 85301b7f..185e2936 100644 --- a/src/meta/mus_acm.c +++ b/src/meta/mus_acm.c @@ -125,7 +125,7 @@ VGMSTREAM * init_vgmstream_mus_acm(STREAMFILE *streamFile) { if (strcasecmp("mus",filename_extension(filename))) goto fail; /* read file name base */ - line_bytes = get_streamfile_dos_line(sizeof(line_buffer),line_buffer, + line_bytes = get_streamfile_text_line(sizeof(line_buffer),line_buffer, mus_offset, streamFile, &whole_line_read); if (!whole_line_read) goto fail; mus_offset += line_bytes; @@ -140,7 +140,7 @@ VGMSTREAM * init_vgmstream_mus_acm(STREAMFILE *streamFile) { /*printf("name base: %s\n",name_base);*/ /* read track entry count */ - line_bytes = get_streamfile_dos_line(sizeof(line_buffer),line_buffer, + line_bytes = get_streamfile_text_line(sizeof(line_buffer),line_buffer, mus_offset, streamFile, &whole_line_read); if (!whole_line_read) goto fail; if (line_buffer[0] == '\0') goto fail; @@ -184,7 +184,7 @@ VGMSTREAM * init_vgmstream_mus_acm(STREAMFILE *streamFile) { { int fields_matched; line_bytes = - get_streamfile_dos_line(sizeof(line_buffer),line_buffer, + get_streamfile_text_line(sizeof(line_buffer),line_buffer, mus_offset, streamFile, &whole_line_read); if (!whole_line_read) goto fail; mus_offset += line_bytes; diff --git a/src/meta/naac.c b/src/meta/naac.c new file mode 100644 index 00000000..b657e598 --- /dev/null +++ b/src/meta/naac.c @@ -0,0 +1,66 @@ +#include "meta.h" +#include "../coding/coding.h" + +/* .NAAC - from Namco 3DS games (Ace Combat - Assault Horizon Legacy, Taiko no Tatsujin Don to Katsu no Jikuu Daibouken) */ +VGMSTREAM * init_vgmstream_naac(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + off_t start_offset; + int loop_flag, channel_count; + size_t data_size; + + /* check extension */ + if ( !check_extensions(streamFile,"naac") ) + goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x41414320) /* "AAC " */ + goto fail; + if (read_32bitLE(0x04,streamFile) != 0x01) /* version? */ + goto fail; + + start_offset = 0x1000; + loop_flag = (read_32bitLE(0x18,streamFile) != 0); + channel_count = read_32bitLE(0x08,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + vgmstream->sample_rate = read_32bitLE(0x0c,streamFile); + vgmstream->num_samples = read_32bitLE(0x10,streamFile); /* without skip_samples */ + vgmstream->loop_start_sample = read_32bitLE(0x14,streamFile); /* with skip_samples */ + vgmstream->loop_end_sample = read_32bitLE(0x18,streamFile); + /* 0x1c: loop start offset, 0x20: loop end offset (within data) */ + data_size = read_32bitLE(0x24,streamFile); + /* 0x28: unknown; 0x2c: table start offset?; 0x30: seek table (always 0xFD0, padded) */ + + vgmstream->meta_type = meta_NAAC; + +#ifdef VGM_USE_FFMPEG + { + ffmpeg_codec_data *ffmpeg_data = NULL; + + ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset,data_size); + if (!ffmpeg_data) goto fail; + vgmstream->codec_data = ffmpeg_data; + vgmstream->coding_type = coding_FFmpeg; + vgmstream->layout_type = layout_none; + + /* observed default, some files start without silence though seems correct when loop_start=0 */ + if (!ffmpeg_data->skipSamples) /* FFmpeg doesn't seem to use not report it */ + ffmpeg_set_skip_samples(ffmpeg_data, 1024); + vgmstream->num_samples -= 1024; + } +#else + goto fail; +#endif + + /* open the file for reading */ + if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} diff --git a/src/meta/ps2_smpl.c b/src/meta/ps2_smpl.c index 0c4b76f5..e44bd7ed 100644 --- a/src/meta/ps2_smpl.c +++ b/src/meta/ps2_smpl.c @@ -1,63 +1,48 @@ #include "meta.h" -#include "../util.h" +#include "../coding/coding.h" -/* SMPL (from Homura) */ +/* SMPL - from Homura (PS2) */ VGMSTREAM * init_vgmstream_ps2_smpl(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; off_t start_offset; + int loop_flag, channel_count; + size_t channel_size; - int loop_flag; - int channel_count; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("smpl",filename_extension(filename))) goto fail; + /* check extension (.v0: left channel, .v1: right channel, .smpl: header id) */ + if ( !check_extensions(streamFile,"v0,v1,smpl") ) + goto fail; /* check header */ if (read_32bitBE(0x00,streamFile) != 0x534D504C) /* "SMPL" */ goto fail; - loop_flag = 1; channel_count = 1; + loop_flag = (read_32bitLE(0x30,streamFile) != 0); /* .v1 doesn't have loop points */ + start_offset = 0x40; + channel_size = read_32bitBE(0x0c,streamFile) - 0x10; - /* build the VGMSTREAM */ + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; - /* fill in the vital statistics */ - start_offset = 0x40; - vgmstream->channels = channel_count; vgmstream->sample_rate = read_32bitBE(0x10,streamFile); - vgmstream->coding_type = coding_PSX_badflags; - vgmstream->num_samples = read_32bitBE(0xc,streamFile)*56/32; - if (loop_flag) { - vgmstream->loop_start_sample = read_32bitLE(0x30,streamFile); - vgmstream->loop_end_sample = vgmstream->num_samples; - } - vgmstream->layout_type = layout_none; + vgmstream->num_samples = ps_bytes_to_samples(channel_size*channel_count, channel_count); + vgmstream->loop_start_sample = read_32bitLE(0x30,streamFile); + vgmstream->loop_end_sample = vgmstream->num_samples; + vgmstream->meta_type = meta_PS2_SMPL; + vgmstream->coding_type = coding_PSX; + vgmstream->layout_type = layout_none; + + /* always, but can be null or used as special string */ + read_string(vgmstream->stream_name,0x10+1, 0x20,streamFile); /* open the file for reading */ - { - int i; - STREAMFILE * file; - file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!file) goto fail; - for (i=0;ich[i].streamfile = file; - - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset+ - vgmstream->interleave_block_size*i; - - } - } - + 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/src/meta/sli.c b/src/meta/sli.c index 78d2950d..a2852667 100644 --- a/src/meta/sli.c +++ b/src/meta/sli.c @@ -54,7 +54,7 @@ VGMSTREAM * init_vgmstream_sli_ogg(STREAMFILE *streamFile) { while ((loop_start == -1 || loop_length == -1) && sli_offset < get_streamfile_size(streamFile)) { char *endptr; char *foundptr; - bytes_read=get_streamfile_dos_line(sizeof(linebuffer),linebuffer,sli_offset,streamFile,&done); + bytes_read=get_streamfile_text_line(sizeof(linebuffer),linebuffer,sli_offset,streamFile,&done); if (!done) goto fail; if (!memcmp("LoopStart=",linebuffer,10) && linebuffer[10]!='\0') { diff --git a/src/meta/txth.c b/src/meta/txth.c index 1e7850a8..b7e4630d 100644 --- a/src/meta/txth.c +++ b/src/meta/txth.c @@ -3,7 +3,7 @@ #include "../layout/layout.h" #include "../util.h" -#define TXTH_LINE_MAX 0x2000 +#define TXT_LINE_MAX 0x2000 /* known TXTH types */ typedef enum { @@ -83,7 +83,7 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) { int i, j; /* no need for ID or ext checks -- if a .TXTH exists all is good - * (player still needs to accept the ext, so at worst rename to .vgmstream) */ + * (player still needs to accept the streamfile's ext, so at worst rename to .vgmstream) */ streamText = open_txth(streamFile); if (!streamText) goto fail; @@ -401,44 +401,28 @@ fail: /* Simple text parser of "key = value" lines. * The code is meh and error handling not exactly the best. */ static int parse_txth(STREAMFILE * streamFile, STREAMFILE * streamText, txth_header * txth) { - off_t off = 0; + off_t txt_offset = 0x00; off_t file_size = get_streamfile_size(streamText); txth->data_size = get_streamfile_size(streamFile); /* for later use */ /* skip BOM if needed */ if (read_16bitLE(0x00, streamText) == 0xFFFE || read_16bitLE(0x00, streamText) == 0xFEFF) - off = 0x02; + txt_offset = 0x02; /* read lines */ - while (off < file_size) { - char line[TXTH_LINE_MAX]; - char key[TXTH_LINE_MAX]; - char val[TXTH_LINE_MAX]; /* at least as big as a line to avoid overflows (I hope) */ - int ok; - off_t line_start = off, line_end = 0; - line[0] = key[0] = val[0] = 0; - - /* find line end */ - while (line_end == 0 && off - line_start < TXTH_LINE_MAX) { - char c = (char)read_8bit(off, streamText); - if (c == '\n') - line_end = off; - else if (off >= file_size) - line_end = off-1; + while (txt_offset < file_size) { + char line[TXT_LINE_MAX] = {0}; + char key[TXT_LINE_MAX] = {0}, val[TXT_LINE_MAX] = {0}; /* at least as big as a line to avoid overflows (I hope) */ + int ok, bytes_read, line_done; - off++; - } + bytes_read = get_streamfile_text_line(TXT_LINE_MAX,line, txt_offset,streamText, &line_done); + if (!line_done) goto fail; - if (line_end == 0) - goto fail; /* bad file / line too long */ + txt_offset += bytes_read; /* get key/val (ignores lead/trail spaces, stops at space/comment/separator) */ - read_streamfile((uint8_t*)line,line_start,line_end, streamText); - line[line_end - line_start + 1] = '\0'; ok = sscanf(line, " %[^ \t#=] = %[^ \t#\r\n] ", key,val); - //VGM_LOG("TXTH: ok=%i, key=\"%s\", val=\"%s\" from 0x%lx to 0x%lx\n", ok, key, val, line_start, line_end); - if (ok != 2) /* ignore line if no key=val (comment or garbage) */ continue; diff --git a/src/streamfile.c b/src/streamfile.c index f1d4d07e..97e54992 100644 --- a/src/streamfile.c +++ b/src/streamfile.c @@ -22,9 +22,6 @@ typedef struct { uint8_t * buffer; /* data buffer */ size_t buffersize; /* max buffer size */ size_t filesize; /* cached file size (max offset) */ -#ifdef VGM_DEBUG_OUTPUT - int error_notified; -#endif #ifdef PROFILE_STREAMFILE size_t bytes_read; int error_count; @@ -67,13 +64,7 @@ static size_t read_the_rest(uint8_t * dest, off_t offset, size_t length, STDIOST /* request outside file: ignore to avoid seek/read */ if (offset > streamfile->filesize) { streamfile->offset = streamfile->filesize; - -#ifdef VGM_DEBUG_OUTPUT - if (!streamfile->error_notified) { - VGM_LOG("ERROR: reading over filesize 0x%x @ 0x%lx + 0x%x (buggy meta?)\n", streamfile->filesize, offset, length); - streamfile->error_notified = 1; - } -#endif + VGM_LOG_ONCE("ERROR: reading over filesize 0x%x @ 0x%lx + 0x%x (buggy meta?)\n", streamfile->filesize, offset, length); #if STREAMFILE_IGNORE_EOF memset(dest,0,length); /* dest is already shifted */ @@ -143,13 +134,7 @@ static size_t read_stdio(STDIOSTREAMFILE *streamfile,uint8_t * dest, off_t offse /* request outside file: ignore to avoid seek/read in read_the_rest() */ if (offset > streamfile->filesize) { streamfile->offset = streamfile->filesize; - -#ifdef VGM_DEBUG_OUTPUT - if (!streamfile->error_notified) { - VGM_LOG("ERROR: offset over filesize 0x%x @ 0x%lx + 0x%x (buggy meta?)\n", streamfile->filesize, offset, length); - streamfile->error_notified = 1; - } -#endif + VGM_LOG_ONCE("ERROR: offset over filesize 0x%x @ 0x%lx + 0x%x (buggy meta?)\n", streamfile->filesize, offset, length); #if STREAMFILE_IGNORE_EOF memset(dest,0,length); @@ -298,63 +283,59 @@ STREAMFILE * open_stdio_streamfile_by_file(FILE * file, const char * filename) { /* **************************************************** */ -/* Read a line into dst. The source files are MS-DOS style, - * separated (not terminated) by CRLF. Return 1 if the full line was - * retrieved (if it could fit in dst), 0 otherwise. In any case the result - * will be properly terminated. The CRLF will be removed if there is one. - * Return the number of bytes read (including CRLF line ending). Note that - * this is not the length of the string, and could be larger than the buffer. - * *line_done_ptr is set to 1 if the complete line was read into dst, - * otherwise it is set to 0. line_done_ptr can be NULL if you aren't - * interested in this info. +/* Read a line into dst. The source files are lines separated by CRLF (Windows) / LF (Unux) / CR (Mac). + * The line will be null-terminated and CR/LF removed if found. + * + * Returns the number of bytes read (including CR/LF), note that this is not the string length. + * line_done_ptr is set to 1 if the complete line was read into dst; NULL can be passed to ignore. */ -size_t get_streamfile_dos_line(int dst_length, char * dst, off_t offset, - STREAMFILE * infile, int *line_done_ptr) -{ +size_t get_streamfile_text_line(int dst_length, char * dst, off_t offset, STREAMFILE * streamfile, int *line_done_ptr) { int i; - off_t file_length = get_streamfile_size(infile); - /* how many bytes over those put in the buffer were read */ - int extra_bytes = 0; + off_t file_length = get_streamfile_size(streamfile); + int extra_bytes = 0; /* how many bytes over those put in the buffer were read */ if (line_done_ptr) *line_done_ptr = 0; - for (i=0;iopen(streamFile,filename_ext,STREAMFILE_DEFAULT_BUFFER_SIZE); } -/* Opens an stream in the same folder */ +/* Opens an stream using the passed name (in the same folder) */ STREAMFILE * open_stream_name(STREAMFILE *streamFile, const char * name) { char foldername[PATH_LIMIT]; char filename[PATH_LIMIT]; diff --git a/src/streamfile.h b/src/streamfile.h index 914f2917..0398b5ae 100644 --- a/src/streamfile.h +++ b/src/streamfile.h @@ -156,7 +156,7 @@ static inline int8_t read_8bit(off_t offset, STREAMFILE * streamfile) { /* various STREAMFILE helpers functions */ -size_t get_streamfile_dos_line(int dst_length, char * dst, off_t offset, STREAMFILE * infile, int *line_done_ptr); +size_t get_streamfile_text_line(int dst_length, char * dst, off_t offset, STREAMFILE * streamfile, int *line_done_ptr); STREAMFILE * open_stream_ext(STREAMFILE *streamFile, const char * ext); STREAMFILE * open_stream_name(STREAMFILE *streamFile, const char * ext); diff --git a/src/util.c b/src/util.c index 5d457d1c..badb2c97 100644 --- a/src/util.c +++ b/src/util.c @@ -2,10 +2,6 @@ #include "util.h" #include "streamtypes.h" -int check_sample_rate(int32_t sr) { - return !(sr<300 || sr>96000); -} - const char * filename_extension(const char * filename) { const char * ext; diff --git a/src/util.h b/src/util.h index 0062e6ac..0325743f 100644 --- a/src/util.h +++ b/src/util.h @@ -61,9 +61,6 @@ static inline int get_low_nibble_signed(uint8_t n) { return nibble_to_int[n&0xf]; } -/* return true for a good sample rate */ -int check_sample_rate(int32_t sr); - /* 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 */ @@ -81,15 +78,19 @@ void concatn(int length, char * dst, const char * src); /* Simple stdout logging for debugging and regression testing purposes. - * Needs C99 variadic macros. */ + * Needs C99 variadic macros, uses do..while to force ; as statement */ #ifdef VGM_DEBUG_OUTPUT /* equivalent to printf when condition is true */ #define VGM_ASSERT(condition, ...) \ do { if (condition) printf(__VA_ARGS__); } while (0) +#define VGM_ASSERT_ONCE(condition, ...) \ + do { static int written; if (!written) { if (condition) printf(__VA_ARGS__); written = 1; } } while (0) /* equivalent to printf */ #define VGM_LOG(...) \ do { printf(__VA_ARGS__); } while (0) +#define VGM_LOG_ONCE(...) \ + do { static int written; if (!written) { printf(__VA_ARGS__); written = 1; } } while (0) /* prints file/line/func */ #define VGM_LOGF() \ do { printf("%s:%i '%s'\n", __FILE__, __LINE__, __func__); } while (0) @@ -111,10 +112,12 @@ void concatn(int length, char * dst, const char * src); #define VGM_ASSERT(condition, ...) /* nothing */ #define VGM_LOG(...) /* nothing */ +#define VGM_LOG_ONCE(...) /* nothing */ #define VGM_LOGF() /* nothing */ #define VGM_LOGT() /* nothing */ #define VGM_LOGB(buf, buf_size, bytes_per_line) /* nothing */ + #endif/*VGM_DEBUG_OUTPUT*/ #endif diff --git a/src/vgmstream.c b/src/vgmstream.c index 7c6c4ef7..a09dd3c8 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -10,16 +10,11 @@ #include "layout/layout.h" #include "coding/coding.h" -/* See if there is a second file which may be the second channel, given - * already opened mono opened_stream which was opened from filename. - * If a suitable file is found, open it and change opened_stream to a stereo stream. */ -static void try_dual_file_stereo(VGMSTREAM * opened_stream, STREAMFILE *streamFile); +static void try_dual_file_stereo(VGMSTREAM * opened_vgmstream, STREAMFILE *streamFile, VGMSTREAM* (*init_vgmstream_function)(STREAMFILE*)); -/* - * List of functions that will recognize files. - */ -VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = { +/* List of functions that will recognize files */ +VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = { init_vgmstream_adx, init_vgmstream_brstm, init_vgmstream_bfwav, @@ -37,7 +32,7 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = { init_vgmstream_ngc_dsp_std, init_vgmstream_ngc_mdsp_std, init_vgmstream_ngc_dsp_csmp, - init_vgmstream_Cstr, + init_vgmstream_cstr, init_vgmstream_gcsw, init_vgmstream_ps2_ads, init_vgmstream_ps2_npsf, @@ -138,7 +133,7 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = { init_vgmstream_dc_str, init_vgmstream_dc_str_v2, init_vgmstream_xbox_matx, - init_vgmstream_de2, + init_vgmstream_dec, init_vgmstream_vs, init_vgmstream_dc_str, init_vgmstream_dc_str_v2, @@ -368,6 +363,7 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = { init_vgmstream_nsw_opus, init_vgmstream_pc_al2, init_vgmstream_pc_ast, + init_vgmstream_naac, init_vgmstream_ubi_sb, init_vgmstream_txth, /* should go at the end (lower priority) */ @@ -378,87 +374,102 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = { /* internal version with all parameters */ -static VGMSTREAM * init_vgmstream_internal(STREAMFILE *streamFile, int do_dfs) { +static VGMSTREAM * init_vgmstream_internal(STREAMFILE *streamFile) { int i, fcns_size; if (!streamFile) return NULL; - fcns_size = (sizeof(init_vgmstream_fcns)/sizeof(init_vgmstream_fcns[0])); + fcns_size = (sizeof(init_vgmstream_functions)/sizeof(init_vgmstream_functions[0])); /* try a series of formats, see which works */ for (i=0; i < fcns_size; i++) { /* call init function and see if valid VGMSTREAM was returned */ - VGMSTREAM * vgmstream = (init_vgmstream_fcns[i])(streamFile); - if (vgmstream) { - /* these are little hacky checks */ + VGMSTREAM * vgmstream = (init_vgmstream_functions[i])(streamFile); + if (!vgmstream) + continue; - /* fail if there is nothing to play (without this check vgmstream can generate empty files) */ - if (vgmstream->num_samples <= 0) { - VGM_LOG("VGMSTREAM: wrong num_samples (ns=%i / 0x%08x)\n", vgmstream->num_samples, vgmstream->num_samples); - close_vgmstream(vgmstream); - continue; - } + /* fail if there is nothing to play (without this check vgmstream can generate empty files) */ + if (vgmstream->num_samples <= 0) { + VGM_LOG("VGMSTREAM: wrong num_samples (ns=%i / 0x%08x)\n", vgmstream->num_samples, vgmstream->num_samples); + close_vgmstream(vgmstream); + continue; + } - /* everything should have a reasonable sample rate (a verification of the metadata) */ - if (!check_sample_rate(vgmstream->sample_rate)) { - VGM_LOG("VGMSTREAM: wrong sample rate (sr=%i)\n", vgmstream->sample_rate); - close_vgmstream(vgmstream); - continue; - } + /* everything should have a reasonable sample rate (300 is Wwise min) */ + if (vgmstream->sample_rate < 300 || vgmstream->sample_rate > 96000) { + VGM_LOG("VGMSTREAM: wrong sample rate (sr=%i)\n", vgmstream->sample_rate); + close_vgmstream(vgmstream); + continue; + } - /* Sanify loops! */ - if (vgmstream->loop_flag) { - if ((vgmstream->loop_end_sample <= vgmstream->loop_start_sample) - || (vgmstream->loop_end_sample > vgmstream->num_samples) - || (vgmstream->loop_start_sample < 0) ) { - vgmstream->loop_flag = 0; - VGM_LOG("VGMSTREAM: wrong loops ignored (lss=%i, lse=%i, ns=%i)\n", vgmstream->loop_start_sample, vgmstream->loop_end_sample, vgmstream->num_samples); - } + /* Sanify loops! */ + if (vgmstream->loop_flag) { + if ((vgmstream->loop_end_sample <= vgmstream->loop_start_sample) + || (vgmstream->loop_end_sample > vgmstream->num_samples) + || (vgmstream->loop_start_sample < 0) ) { + vgmstream->loop_flag = 0; + VGM_LOG("VGMSTREAM: wrong loops ignored (lss=%i, lse=%i, ns=%i)\n", vgmstream->loop_start_sample, vgmstream->loop_end_sample, vgmstream->num_samples); } + } - /* dual file stereo */ - if (do_dfs && ( - (vgmstream->meta_type == meta_DSP_STD) || - (vgmstream->meta_type == meta_PS2_VAGp) || - (vgmstream->meta_type == meta_GENH) || - (vgmstream->meta_type == meta_KRAW) || - (vgmstream->meta_type == meta_PS2_MIB) || - (vgmstream->meta_type == meta_NGC_LPS) || - (vgmstream->meta_type == meta_DSP_YGO) || - (vgmstream->meta_type == meta_DSP_AGSC) || - (vgmstream->meta_type == meta_PS2_SMPL) || - (vgmstream->meta_type == meta_NGCA) || - (vgmstream->meta_type == meta_NUB_VAG) || - (vgmstream->meta_type == meta_SPT_SPD) || - (vgmstream->meta_type == meta_EB_SFX) || - (vgmstream->meta_type == meta_CWAV) - ) && vgmstream->channels == 1) { - try_dual_file_stereo(vgmstream, streamFile); + /* test if candidate for dual stereo */ + if (vgmstream->channels == 1 && ( + (vgmstream->meta_type == meta_DSP_STD) || + (vgmstream->meta_type == meta_PS2_VAGp) || + (vgmstream->meta_type == meta_GENH) || + (vgmstream->meta_type == meta_TXTH) || + (vgmstream->meta_type == meta_KRAW) || + (vgmstream->meta_type == meta_PS2_MIB) || + (vgmstream->meta_type == meta_NGC_LPS) || + (vgmstream->meta_type == meta_DSP_YGO) || + (vgmstream->meta_type == meta_DSP_AGSC) || + (vgmstream->meta_type == meta_PS2_SMPL) || + (vgmstream->meta_type == meta_NGCA) || + (vgmstream->meta_type == meta_NUB_VAG) || + (vgmstream->meta_type == meta_SPT_SPD) || + (vgmstream->meta_type == meta_EB_SFX) || + (vgmstream->meta_type == meta_CWAV) + )) { + try_dual_file_stereo(vgmstream, streamFile, init_vgmstream_functions[i]); + } + + +#ifdef VGM_DEBUG_OUTPUT +#ifdef VGM_USE_FFMPEG + /* debug fun */ + if (vgmstream->coding_type != coding_FFmpeg){ + int i = 0; + + /* probable segfault but some layouts/codecs can ignore these */ + for (i = 0; i < vgmstream->channels; i++) { + VGM_ASSERT(vgmstream->ch[i].streamfile == NULL, "VGMSTREAM: null streamfile in ch%i\n",i); } + } +#endif +#endif/*VGM_DEBUG_OUTPUT*/ + #ifdef VGM_USE_FFMPEG - /* check FFmpeg streams here, for lack of a better place */ - if (vgmstream->coding_type == coding_FFmpeg) { - ffmpeg_codec_data *data = (ffmpeg_codec_data *) vgmstream->codec_data; - if (data->streamCount && !vgmstream->num_streams) { - vgmstream->num_streams = data->streamCount; - } + /* check FFmpeg streams here, for lack of a better place */ + if (vgmstream->coding_type == coding_FFmpeg) { + ffmpeg_codec_data *data = (ffmpeg_codec_data *) vgmstream->codec_data; + if (data->streamCount && !vgmstream->num_streams) { + vgmstream->num_streams = data->streamCount; } + } #endif - /* save info */ - vgmstream->stream_index = streamFile->stream_index; + /* save info */ + vgmstream->stream_index = streamFile->stream_index; - /* save start things so we can restart for seeking */ - /* copy the channels */ - memcpy(vgmstream->start_ch,vgmstream->ch,sizeof(VGMSTREAMCHANNEL)*vgmstream->channels); - /* copy the whole VGMSTREAM */ - memcpy(vgmstream->start_vgmstream,vgmstream,sizeof(VGMSTREAM)); + /* save start things so we can restart for seeking */ + memcpy(vgmstream->start_ch,vgmstream->ch,sizeof(VGMSTREAMCHANNEL)*vgmstream->channels); + memcpy(vgmstream->start_vgmstream,vgmstream,sizeof(VGMSTREAM)); - return vgmstream; - } + return vgmstream; } + /* not supported */ return NULL; } @@ -474,7 +485,7 @@ VGMSTREAM * init_vgmstream(const char * const filename) { } VGMSTREAM * init_vgmstream_from_STREAMFILE(STREAMFILE *streamFile) { - return init_vgmstream_internal(streamFile,1); + return init_vgmstream_internal(streamFile); } /* Reset a VGMSTREAM to its state at the start of playback. @@ -913,14 +924,14 @@ void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstre case layout_ast_blocked: case layout_halpst_blocked: case layout_xa_blocked: - case layout_ea_blocked: + case layout_blocked_ea_schl: case layout_blocked_ea_1snh: case layout_caf_blocked: case layout_wsi_blocked: case layout_str_snds_blocked: case layout_ws_aud_blocked: case layout_matx_blocked: - case layout_de2_blocked: + case layout_blocked_dec: case layout_vs_blocked: case layout_emff_ps2_blocked: case layout_emff_ngc_blocked: @@ -928,7 +939,7 @@ void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstre case layout_xvas_blocked: case layout_thp_blocked: case layout_filp_blocked: - case layout_ivaud_blocked: + case layout_blocked_ivaud: case layout_psx_mgav_blocked: case layout_ps2_adm_blocked: case layout_dsp_bdsp_blocked: @@ -937,7 +948,7 @@ void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstre case layout_ps2_strlr_blocked: case layout_rws_blocked: case layout_hwas_blocked: - case layout_ea_sns_blocked: + case layout_blocked_ea_sns: case layout_blocked_awc: case layout_blocked_vgs: render_vgmstream_blocked(buffer,sample_count,vgmstream); @@ -1960,6 +1971,7 @@ int vgmstream_do_loop(VGMSTREAM * vgmstream) { vgmstream->current_sample = vgmstream->loop_sample; vgmstream->samples_into_block = vgmstream->loop_samples_into_block; vgmstream->current_block_size = vgmstream->loop_block_size; + vgmstream->current_block_samples = vgmstream->loop_block_samples; vgmstream->current_block_offset = vgmstream->loop_block_offset; vgmstream->next_block_offset = vgmstream->loop_next_block_offset; @@ -1975,6 +1987,7 @@ int vgmstream_do_loop(VGMSTREAM * vgmstream) { vgmstream->loop_sample = vgmstream->current_sample; vgmstream->loop_samples_into_block = vgmstream->samples_into_block; vgmstream->loop_block_size = vgmstream->current_block_size; + vgmstream->loop_block_samples = vgmstream->current_block_samples; vgmstream->loop_block_offset = vgmstream->current_block_offset; vgmstream->loop_next_block_offset = vgmstream->next_block_offset; vgmstream->hit_loop = 1; @@ -2136,104 +2149,108 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) { } } -/* filename search pairs for dual file stereo */ -const char * const dfs_pairs[][2] = { - {"L","R"}, - {"l","r"}, - {"_0","_1"}, - {"left","right"}, - {"Left","Right"}, -}; -#define DFS_PAIR_COUNT (sizeof(dfs_pairs)/sizeof(dfs_pairs[0])) -static void try_dual_file_stereo(VGMSTREAM * opened_stream, STREAMFILE *streamFile) { - char filename[PATH_LIMIT]; - char filename2[PATH_LIMIT]; +/* See if there is a second file which may be the second channel, given an already opened mono vgmstream. + * If a suitable file is found, open it and change opened_vgmstream to a stereo vgmstream. */ +static void try_dual_file_stereo(VGMSTREAM * opened_vgmstream, STREAMFILE *streamFile, VGMSTREAM*(*init_vgmstream_function)(STREAMFILE *)) { + /* filename search pairs for dual file stereo */ + static const char * const dfs_pairs[][2] = { + {"L","R"}, + {"l","r"}, + {"left","right"}, + {"Left","Right"}, + {".V0",".V1"}, + {"_0","_1"}, //unneeded? + }; + char new_filename[PATH_LIMIT]; char * ext; - int dfs_name= -1; /*-1=no stereo, 0=opened_stream is left, 1=opened_stream is right */ - VGMSTREAM * new_stream = NULL; - STREAMFILE *dual_stream = NULL; - int i,j; + int dfs_pair = -1; /* -1=no stereo, 0=opened_vgmstream is left, 1=opened_vgmstream is right */ + VGMSTREAM *new_vgmstream = NULL; + STREAMFILE *dual_streamFile = NULL; + int i,j, dfs_pair_count; - if (opened_stream->channels != 1) return; - - streamFile->get_name(streamFile,filename,sizeof(filename)); + if (opened_vgmstream->channels != 1) + return; /* vgmstream's layout stuff currently assumes a single file */ // fastelbja : no need ... this one works ok with dual file - //if (opened_stream->layout != layout_none) return; + //if (opened_vgmstream->layout != layout_none) return; + //todo force layout_none if layout_interleave? - /* we need at least a base and a name ending to replace */ - if (strlen(filename)<2) return; + streamFile->get_name(streamFile,new_filename,sizeof(new_filename)); + if (strlen(new_filename)<2) return; /* we need at least a base and a name ending to replace */ + + ext = (char *)filename_extension(new_filename); + if (ext-new_filename >= 1 && ext[-1]=='.') ext--; /* including "." */ - strcpy(filename2,filename); + /* find pair from base name and modify new_filename with the opposite */ + dfs_pair_count = (sizeof(dfs_pairs)/sizeof(dfs_pairs[0])); + for (i = 0; dfs_pair == -1 && i< dfs_pair_count; i++) { + for (j=0; dfs_pair==-1 && j<2; j++) { + const char * this_suffix = dfs_pairs[i][j]; + size_t this_suffix_len = strlen(dfs_pairs[i][j]); + const char * other_suffix = dfs_pairs[i][j^1]; + size_t other_suffix_len = strlen(dfs_pairs[i][j^1]); - /* look relative to the extension; */ - ext = (char *)filename_extension(filename2); - - /* we treat the . as part of the extension */ - if (ext-filename2 >= 1 && ext[-1]=='.') ext--; - - for (i=0; dfs_name==-1 && iopen(streamFile,filename2,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!dual_stream) goto fail; + /* try to init other channel (new_filename now has the opposite name) */ + dual_streamFile = streamFile->open(streamFile,new_filename,STREAMFILE_DEFAULT_BUFFER_SIZE); + if (!dual_streamFile) goto fail; - new_stream = init_vgmstream_internal(dual_stream, - 0 /* don't do dual file on this, to prevent recursion */ - ); - close_streamfile(dual_stream); + new_vgmstream = init_vgmstream_function(dual_streamFile); /* use the init that just worked, no other should work */ + close_streamfile(dual_streamFile); /* see if we were able to open the file, and if everything matched nicely */ - if (new_stream && - new_stream->channels == 1 && - /* we have seen legitimate pairs where these are off by one... */ - /* but leaving it commented out until I can find those and recheck */ - /* abs(new_stream->num_samples-opened_stream->num_samples <= 1) && */ - new_stream->num_samples == opened_stream->num_samples && - new_stream->sample_rate == opened_stream->sample_rate && - new_stream->meta_type == opened_stream->meta_type && - new_stream->coding_type == opened_stream->coding_type && - new_stream->layout_type == opened_stream->layout_type && - new_stream->loop_flag == opened_stream->loop_flag && - /* check these even if there is no loop, because they should then - * be zero in both */ - new_stream->loop_start_sample == opened_stream->loop_start_sample && - new_stream->loop_end_sample == opened_stream->loop_end_sample && + if (!(new_vgmstream && + new_vgmstream->channels == 1 && + /* we have seen legitimate pairs where these are off by one... + * but leaving it commented out until I can find those and recheck */ + /* abs(new_vgmstream->num_samples-opened_vgmstream->num_samples <= 1) && */ + new_vgmstream->num_samples == opened_vgmstream->num_samples && + new_vgmstream->sample_rate == opened_vgmstream->sample_rate && + new_vgmstream->meta_type == opened_vgmstream->meta_type && + new_vgmstream->coding_type == opened_vgmstream->coding_type && + new_vgmstream->layout_type == opened_vgmstream->layout_type && /* check even if the layout doesn't use them, because it is - * difficult to determine when it does, and they should be zero - * otherwise, anyway */ - new_stream->interleave_block_size == opened_stream->interleave_block_size && - new_stream->interleave_smallblock_size == opened_stream->interleave_smallblock_size) { - /* We seem to have a usable, matching file. Merge in the second channel. */ + * difficult to determine when it does, and they should be zero otherwise, anyway */ + new_vgmstream->interleave_block_size == opened_vgmstream->interleave_block_size && + new_vgmstream->interleave_smallblock_size == opened_vgmstream->interleave_smallblock_size)) { + goto fail; + } + + /* check these even if there is no loop, because they should then be zero in both + * Homura PS2 right channel doesn't have loop points so it's ignored */ + if (new_vgmstream->meta_type != meta_PS2_SMPL && + !(new_vgmstream->loop_flag == opened_vgmstream->loop_flag && + new_vgmstream->loop_start_sample== opened_vgmstream->loop_start_sample && + new_vgmstream->loop_end_sample == opened_vgmstream->loop_end_sample)) { + goto fail; + } + + /* We seem to have a usable, matching file. Merge in the second channel. */ + { VGMSTREAMCHANNEL * new_chans; VGMSTREAMCHANNEL * new_loop_chans = NULL; VGMSTREAMCHANNEL * new_start_chans = NULL; @@ -2242,18 +2259,17 @@ static void try_dual_file_stereo(VGMSTREAM * opened_stream, STREAMFILE *streamFi new_chans = calloc(2,sizeof(VGMSTREAMCHANNEL)); if (!new_chans) goto fail; - memcpy(&new_chans[dfs_name],&opened_stream->ch[0],sizeof(VGMSTREAMCHANNEL)); - memcpy(&new_chans[dfs_name^1],&new_stream->ch[0],sizeof(VGMSTREAMCHANNEL)); + memcpy(&new_chans[dfs_pair],&opened_vgmstream->ch[0],sizeof(VGMSTREAMCHANNEL)); + memcpy(&new_chans[dfs_pair^1],&new_vgmstream->ch[0],sizeof(VGMSTREAMCHANNEL)); - /* loop and start will be initialized later, we just need to - * allocate them here */ + /* loop and start will be initialized later, we just need to allocate them here */ new_start_chans = calloc(2,sizeof(VGMSTREAMCHANNEL)); if (!new_start_chans) { free(new_chans); goto fail; } - if (opened_stream->loop_ch) { + if (opened_vgmstream->loop_ch) { new_loop_chans = calloc(2,sizeof(VGMSTREAMCHANNEL)); if (!new_loop_chans) { free(new_chans); @@ -2264,28 +2280,29 @@ static void try_dual_file_stereo(VGMSTREAM * opened_stream, STREAMFILE *streamFi /* remove the existing structures */ /* not using close_vgmstream as that would close the file */ - free(opened_stream->ch); - free(new_stream->ch); + free(opened_vgmstream->ch); + free(new_vgmstream->ch); - free(opened_stream->start_ch); - free(new_stream->start_ch); + free(opened_vgmstream->start_ch); + free(new_vgmstream->start_ch); - if (opened_stream->loop_ch) { - free(opened_stream->loop_ch); - free(new_stream->loop_ch); + if (opened_vgmstream->loop_ch) { + free(opened_vgmstream->loop_ch); + free(new_vgmstream->loop_ch); } /* fill in the new structures */ - opened_stream->ch = new_chans; - opened_stream->start_ch = new_start_chans; - opened_stream->loop_ch = new_loop_chans; + opened_vgmstream->ch = new_chans; + opened_vgmstream->start_ch = new_start_chans; + opened_vgmstream->loop_ch = new_loop_chans; /* stereo! */ - opened_stream->channels = 2; + opened_vgmstream->channels = 2; /* discard the second VGMSTREAM */ - free(new_stream); + free(new_vgmstream); } + fail: return; } diff --git a/src/vgmstream.h b/src/vgmstream.h index 5c749af4..80fe526c 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -212,14 +212,14 @@ typedef enum { layout_ast_blocked, layout_halpst_blocked, layout_xa_blocked, - layout_ea_blocked, + layout_blocked_ea_schl, layout_blocked_ea_1snh, layout_caf_blocked, layout_wsi_blocked, layout_str_snds_blocked, layout_ws_aud_blocked, layout_matx_blocked, - layout_de2_blocked, + layout_blocked_dec, layout_xvas_blocked, layout_vs_blocked, layout_emff_ps2_blocked, @@ -231,15 +231,15 @@ typedef enum { layout_ps2_adm_blocked, layout_dsp_bdsp_blocked, layout_mxch_blocked, - layout_ivaud_blocked, /* GTA IV .ivaud blocks */ + layout_blocked_ivaud, /* GTA IV .ivaud blocks */ layout_tra_blocked, /* DefJam Rapstar .tra blocks */ layout_ps2_iab_blocked, layout_ps2_strlr_blocked, layout_rws_blocked, layout_hwas_blocked, - layout_ea_sns_blocked, /* newest Electronic Arts blocks, found in SNS/SNU/SPS/etc formats */ + layout_blocked_ea_sns, /* newest Electronic Arts blocks, found in SNS/SNU/SPS/etc formats */ layout_blocked_awc, /* Rockstar AWC */ - layout_blocked_vgs, /* Guitar Hero II */ + layout_blocked_vgs, /* Guitar Hero II (PS2) */ /* otherwise odd */ layout_acm, /* libacm layout */ @@ -281,7 +281,7 @@ typedef enum { /* Nintendo */ meta_STRM, /* Nintendo STRM */ - meta_RSTM, /* Nintendo RSTM (similar to STRM) */ + meta_RSTM, /* Nintendo RSTM (Revolution Stream, similar to STRM) */ meta_AFC, /* AFC */ meta_AST, /* AST */ meta_RWSD, /* single-stream RWSD */ @@ -306,7 +306,6 @@ typedef enum { meta_UTF_DSP, /* CRI ADPCM_WII, like AAX with DSP */ meta_NGC_ADPDTK, /* NGC DTK/ADP (.adp/dkt DTK) [no header_id] */ - meta_kRAW, /* almost headerless PCM */ meta_RSF, /* Retro Studios RSF (Metroid Prime .rsf) [no header_id] */ meta_HALPST, /* HAL Labs HALPST */ meta_GCSW, /* GCSW (PCM) */ @@ -470,7 +469,7 @@ typedef enum { meta_WS_AUD, /* Westwood Studios .aud */ meta_WS_AUD_old, /* Westwood Studios .aud, old style */ meta_RIFF_WAVE, /* RIFF, for WAVs */ - meta_RIFF_WAVE_POS, /* .wav + .pos for looping */ + meta_RIFF_WAVE_POS, /* .wav + .pos for looping (Ys Complete PC) */ meta_RIFF_WAVE_labl, /* RIFF w/ loop Markers in LIST-adtl-labl */ meta_RIFF_WAVE_smpl, /* RIFF w/ loop data in smpl chunk */ meta_RIFF_WAVE_MWV, /* .mwv RIFF w/ loop data in ctrl chunk pflt */ @@ -487,7 +486,7 @@ typedef enum { meta_DC_KCEY, /* Konami KCE Yokohama KCEYCOMP (DC games) */ meta_ACM, /* InterPlay ACM header */ meta_MUS_ACM, /* MUS playlist of InterPlay ACM files */ - meta_DE2, /* Falcom (Gurumin) .de2 */ + meta_DEC, /* Falcom PC games (Xanadu Next, Gurumin) */ meta_VS, /* Men in Black .vs */ meta_FFXI_BGW, /* FFXI (PC) BGW */ meta_FFXI_SPW, /* FFXI (PC) SPW */ @@ -590,8 +589,8 @@ typedef enum { meta_PS2_2PFS, // Konami: Mahoromatic: Moetto - KiraKira Maid-San, GANTZ (PS2) meta_PS2_VBK, // Disney's Stitch - Experiment 626 meta_OTM, // Otomedius (Arcade) - meta_CSTM, // Nintendo 3DS CSTM - meta_FSTM, // Nintendo Wii U FSTM + meta_CSTM, // Nintendo 3DS CSTM (Century Stream) + meta_FSTM, // Nintendo Wii U FSTM (caFe? Stream) meta_3DS_IDSP, // Nintendo 3DS/Wii U IDSP meta_KT_WIIBGM, // Koei Tecmo WiiBGM meta_MCA, /* Capcom MCA "MADP" */ @@ -627,6 +626,7 @@ typedef enum { meta_NSW_OPUS, /* Lego City Undercover (Switch) */ meta_PC_AL2, /* Conquest of Elysium 3 (PC) */ meta_PC_AST, /* Dead Rising (PC) */ + meta_NAAC, /* Namco AAC (3DS) */ meta_UBI_SB, /* Ubisoft banks */ #ifdef VGM_USE_VORBIS @@ -717,40 +717,36 @@ typedef struct { char stream_name[STREAM_NAME_SIZE]; /* name of the current stream (info), if the file stores it and it's filled */ /* looping */ - int loop_flag; /* is this stream looped? */ - int32_t loop_start_sample; /* first sample of the loop (included in the loop) */ - int32_t loop_end_sample; /* last sample of the loop (not included in the loop) */ + int loop_flag; /* is this stream looped? */ + int32_t loop_start_sample; /* first sample of the loop (included in the loop) */ + int32_t loop_end_sample; /* last sample of the loop (not included in the loop) */ - /* channels */ - VGMSTREAMCHANNEL * ch; /* pointer to array of channels */ + /* layouts/block */ + size_t interleave_block_size; /* interleave for this file */ + size_t interleave_smallblock_size; /* smaller interleave for last block */ + size_t full_block_size; /* fixed data size, from header (may include padding and other unusable data) */ - /* channel copies */ + /* channel state */ + VGMSTREAMCHANNEL * ch; /* pointer to array of channels */ VGMSTREAMCHANNEL * start_ch; /* copies of channel status as they were at the beginning of the stream */ VGMSTREAMCHANNEL * loop_ch; /* copies of channel status as they were at the loop point */ - /* layout-specific */ + /* layout/block state */ int32_t current_sample; /* number of samples we've passed */ int32_t samples_into_block; /* number of samples into the current block */ - /* interleave */ - size_t interleave_block_size; /* interleave for this file */ - size_t interleave_smallblock_size; /* smaller interleave for last block */ - /* headered blocks */ off_t current_block_offset; /* start of this block (offset of block header) */ size_t current_block_size; /* size in usable bytes of the block we're in now (used to calculate num_samples per block) */ size_t current_block_samples; /* size in samples of the block we're in now (used over current_block_size if possible) */ - size_t full_block_size; /* size including padding and other unusable data */ off_t next_block_offset; /* offset of header of the next block */ - int block_count; /* count of "semi" block in total block */ - - - /* loop layout (saved values) */ + /* layout/block loop state */ int32_t loop_sample; /* saved from current_sample, should be loop_start_sample... */ int32_t loop_samples_into_block;/* saved from samples_into_block */ off_t loop_block_offset; /* saved from current_block_offset */ size_t loop_block_size; /* saved from current_block_size */ + size_t loop_block_samples; /* saved from current_block_samples */ off_t loop_next_block_offset; /* saved from next_block_offset */ - /* loop internals */ + /* loop state */ int hit_loop; /* have we seen the loop yet? */ /* counters for "loop + play end of the stream instead of fading" (not used/needed otherwise) */ int loop_count; /* number of complete loops (1=looped once) */