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) */