Merge pull request #145 from bnnm/naac-dec-smpl-cleanup

NAAC, DEC, SMPL, cleanup
This commit is contained in:
Christopher Snowhill 2017-11-25 17:33:12 -08:00 committed by GitHub
commit cc59db8713
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 1082 additions and 872 deletions

View File

@ -10,10 +10,10 @@ There are multiple end-user bits:
- an XMPlay plugin called "xmp-vgmstream" - an XMPlay plugin called "xmp-vgmstream"
- an Audacious plugin called "libvgmstream" - an Audacious plugin called "libvgmstream"
## IMPORTANT!! ## Needed files (for Windows)
### Needed files (for Windows) Since Ogg Vorbis, MPEG audio, and other external formats are supported, you
Since Ogg Vorbis, MPEG audio, and other formats are now supported, you will will need to have certain DLL files.
need to have certain DLL files.<br/>
In the case of the foobar2000 component they are all bundled for convenience, 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 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). (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```, ```at3plusdecoder.dll```, ```avcodec-vgmstream-58.dll```, ```avformat-vgmstream-58.dll```,
```avutil-vgmstream-56.dll``` and ```swresample-vgmstream-3.dll``` somewhere Windows can ```avutil-vgmstream-56.dll``` and ```swresample-vgmstream-3.dll``` somewhere Windows can
find them. 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. system directory, or any other directory in the PATH variable.
### ```test.exe``` ### test.exe
``` ```
Usage: ./test [-o outfile.wav] [-l loop count] Usage: test.exe [-o outfile.wav] [options] infile
[-f fade time] [-d fade delay] [-ipcmxeE] infile
Options: Options:
-o outfile.wav: name of output .wav file, default is dump.wav -o outfile.wav: name of output .wav file, default is dump.wav
-l loop count: loop count, default 2.0 -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 ### Audacious plugin
Needs to be manually built. Instructions can be found in the source files. 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 As manakoAT likes to say, the extension doesn't really mean anything, but it's
the most obvious way to identify files. 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) - .bgw (PSX configurable ADPCM)
- .bnsf (G.722.1) - .bnsf (G.722.1)
- .caf (Apple IMA4 ADPCM, others) - .caf (Apple IMA4 ADPCM, others)
- .de2 (MS ADPCM) - .dec/de2 (MS ADPCM)
- .hca (CRI High Compression Audio) - .hca (CRI High Compression Audio)
- .pcm/kcey (DVI IMA ADPCM) - .pcm/kcey (DVI IMA ADPCM)
- .lsf (LSF ADPCM) - .lsf (LSF ADPCM)

View File

@ -100,6 +100,7 @@ VGMSTREAM_DECLARE_FILE_TYPE("DBM", dbm);
VGMSTREAM_DECLARE_FILE_TYPE("DCS", dcs); VGMSTREAM_DECLARE_FILE_TYPE("DCS", dcs);
VGMSTREAM_DECLARE_FILE_TYPE("DDSP", ddsp); VGMSTREAM_DECLARE_FILE_TYPE("DDSP", ddsp);
VGMSTREAM_DECLARE_FILE_TYPE("DE2", de2); VGMSTREAM_DECLARE_FILE_TYPE("DE2", de2);
VGMSTREAM_DECLARE_FILE_TYPE("DEC", dec);
VGMSTREAM_DECLARE_FILE_TYPE("DMSG", dmsg); VGMSTREAM_DECLARE_FILE_TYPE("DMSG", dmsg);
VGMSTREAM_DECLARE_FILE_TYPE("DSP", dsp); VGMSTREAM_DECLARE_FILE_TYPE("DSP", dsp);
VGMSTREAM_DECLARE_FILE_TYPE("DSPW", dspw); 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("MxSt", mxst);
VGMSTREAM_DECLARE_FILE_TYPE("MYSPD", myspd); VGMSTREAM_DECLARE_FILE_TYPE("MYSPD", myspd);
VGMSTREAM_DECLARE_FILE_TYPE("NAAC", naac);
VGMSTREAM_DECLARE_FILE_TYPE("NDP", ndp); VGMSTREAM_DECLARE_FILE_TYPE("NDP", ndp);
VGMSTREAM_DECLARE_FILE_TYPE("NGCA", ngca); VGMSTREAM_DECLARE_FILE_TYPE("NGCA", ngca);
VGMSTREAM_DECLARE_FILE_TYPE("NPS", nps); 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("XWS", xws);
VGMSTREAM_DECLARE_FILE_TYPE("XWV", xwv); VGMSTREAM_DECLARE_FILE_TYPE("XWV", xwv);
VGMSTREAM_DECLARE_FILE_TYPE("V0", v0);
VGMSTREAM_DECLARE_FILE_TYPE("YDSP", ydsp); VGMSTREAM_DECLARE_FILE_TYPE("YDSP", ydsp);
VGMSTREAM_DECLARE_FILE_TYPE("YMF", ymf); VGMSTREAM_DECLARE_FILE_TYPE("YMF", ymf);

View File

@ -413,6 +413,7 @@ bool input_vgmstream::get_description_tag(pfc::string_base & temp, pfc::string_b
eos = description.find_first(delimiter, pos); eos = description.find_first(delimiter, pos);
if (eos == pfc::infinite_size) eos = description.length(); if (eos == pfc::infinite_size) eos = description.length();
temp.set_string(description + pos, eos - pos); temp.set_string(description + pos, eos - pos);
//console::formatter() << "tag=" << tag << ", delim=" << delimiter << "temp=" << temp << ", pos=" << pos << "" << eos;
return true; return true;
} }
return false; return false;

View File

@ -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) */ /* 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; int sample_nibble, sample_decoded, step, delta;
sample_nibble = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift)&0xf; 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) */ /* 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; int sample_nibble, sample_decoded, step, delta;
sample_nibble = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift)&0xf; 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; 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 */ /* 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) { 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; 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); *hist1 = clamp16(sample_decoded);
} }
/* *** */ /* ************************************ */
/* DVI/IMA */
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; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
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);
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; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
off_t byte_offset = stream->offset + 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; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
off_t byte_offset = stream->offset + 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; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
off_t byte_offset = stream->offset + 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; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
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);
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; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
int nibble_shift;
offset = (channelspacing==1) ?
stream->offset + 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;
}
/* Standard DVI/IMA ADPCM (as in, ADPCM recommended by the IMA using Intel/DVI's implementation). /* 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. * 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) ? 4:0) : (!(i&1) ? 4:0) : /* even = high, odd = low */
is_stereo ? (!(channel&1) ? 0:4) : (!(i&1) ? 0:4); /* even = low, odd = high */ 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); 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; 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; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
off_t byte_offset = (stream->offset + 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) { 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; int i, sample_count;
@ -558,6 +272,300 @@ void decode_otns_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample *
stream->adpcm_step_index = step_index; 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; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
off_t byte_offset = stream->offset + 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; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
int nibble_shift;
offset = (channelspacing==1) ?
stream->offset + 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; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
off_t byte_offset = stream->offset + 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; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
off_t byte_offset = stream->offset + 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; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
off_t byte_offset = stream->offset + 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; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
off_t byte_offset = stream->offset + 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; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
off_t byte_offset = (stream->offset + 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) { 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; 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 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 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); 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) //last nibble/sample in block is ignored (next header sample contains it)
if (i < block_samples) { 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); outbuf[sample_count] = (short)(hist1);
sample_count+=channelspacing; sample_count+=channelspacing;
//todo atenuation: apparently from hcs's analysis Wwise IMA decodes nibbles slightly different, reducing dbs //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; 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 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); 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; off_t byte_offset = stream->offset + 4 + i/2;
int nibble_shift = (i&1?4:0); //low nibble first 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); outbuf[sample_count] = (short)(hist1);
} }

View File

@ -238,7 +238,7 @@ static void decode_mpeg_standard(VGMSTREAMCHANNEL *stream, mpeg_codec_data * dat
/* end of stream, fill rest with 0s */ /* end of stream, fill rest with 0s */
if (!data->bytes_in_buffer) { 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; break;
} }

View File

@ -164,7 +164,7 @@ void decode_vorbis_custom(VGMSTREAM * vgmstream, sample * outbuf, int32_t sample
decode_fail: decode_fail:
/* on error just put some 0 samples */ /* 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) */ /* converts from internal Vorbis format to standard PCM (mostly from Xiph's decoder_example.c) */

View File

@ -93,6 +93,7 @@ static const char* extension_list[] = {
"dcs", "dcs",
"ddsp", "ddsp",
"de2", "de2",
"dec",
"dmsg", "dmsg",
"dsp", "dsp",
"dspw", "dspw",
@ -192,6 +193,7 @@ static const char* extension_list[] = {
"mxst", "mxst",
"myspd", "myspd",
"naac",
"ndp", "ndp",
"ngca", "ngca",
"nps", "nps",
@ -265,7 +267,7 @@ static const char* extension_list[] = {
"sl3", "sl3",
"sli", "sli",
"smp", "smp",
"smpl", "smpl", //fake extension (to be removed)
"snd", "snd",
"snds", "snds",
"sng", "sng",
@ -307,6 +309,8 @@ static const char* extension_list[] = {
"ulw", "ulw",
"um3", "um3",
"v0",
//"v1", //dual channel with v0
"vag", "vag",
"vas", "vas",
"vawx", "vawx",
@ -517,7 +521,7 @@ static const layout_info layout_info_list[] = {
{layout_ast_blocked, "AST blocked"}, {layout_ast_blocked, "AST blocked"},
{layout_halpst_blocked, "HALPST blocked"}, {layout_halpst_blocked, "HALPST blocked"},
{layout_xa_blocked, "CD-ROM XA"}, {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_blocked_ea_1snh, "blocked (EA 1SNh)"},
{layout_caf_blocked, "CAF blocked"}, {layout_caf_blocked, "CAF blocked"},
{layout_wsi_blocked, ".wsi 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_str_snds_blocked, ".str SNDS blocked"},
{layout_ws_aud_blocked, "Westwood Studios .aud blocked"}, {layout_ws_aud_blocked, "Westwood Studios .aud blocked"},
{layout_matx_blocked, "Matrix .matx blocked"}, {layout_matx_blocked, "Matrix .matx blocked"},
{layout_de2_blocked, "de2 blocked"}, {layout_blocked_dec, "blocked (DEC)"},
{layout_vs_blocked, "vs blocked"}, {layout_vs_blocked, "vs blocked"},
{layout_emff_ps2_blocked, "EMFF (PS2) blocked"}, {layout_emff_ps2_blocked, "EMFF (PS2) blocked"},
{layout_emff_ngc_blocked, "EMFF (NGC/WII) 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_psx_mgav_blocked, "MGAV blocked"},
{layout_ps2_adm_blocked, "ADM blocked"}, {layout_ps2_adm_blocked, "ADM blocked"},
{layout_dsp_bdsp_blocked, "DSP 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_iab_blocked, "IAB blocked"},
{layout_ps2_strlr_blocked, "The Bouncer STR blocked"}, {layout_ps2_strlr_blocked, "The Bouncer STR blocked"},
{layout_rws_blocked, "RWS 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_aix, "AIX interleave, internally 18-byte interleaved"},
{layout_aax, "AAX blocked, 18-byte interleaved"}, {layout_aax, "AAX blocked, 18-byte interleaved"},
{layout_scd_int, "SCD multistream interleave"}, {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_awc, "blocked (AWC)"},
{layout_blocked_vgs, "blocked (VGS)"}, {layout_blocked_vgs, "blocked (VGS)"},
#ifdef VGM_USE_VORBIS #ifdef VGM_USE_VORBIS
@ -568,8 +572,8 @@ static const meta_info meta_info_list[] = {
{meta_UTF_DSP, "CRI ADPCM_WII header"}, {meta_UTF_DSP, "CRI ADPCM_WII header"},
{meta_DSP_AGSC, "Retro Studios AGSC header"}, {meta_DSP_AGSC, "Retro Studios AGSC header"},
{meta_DSP_CSMP, "Retro Studios CSMP header"}, {meta_DSP_CSMP, "Retro Studios CSMP header"},
{meta_NGC_ADPDTK, "assumed Nintendo ADP by .adp extension and valid first frame"}, {meta_NGC_ADPDTK, "Nintendo ADP raw header"},
{meta_RSF, "assumed Retro Studios RSF by .rsf extension and valid first bytes"}, {meta_RSF, "Retro Studios RSF raw header"},
{meta_AFC, "Nintendo AFC header"}, {meta_AFC, "Nintendo AFC header"},
{meta_AST, "Nintendo AST header"}, {meta_AST, "Nintendo AST header"},
{meta_HALPST, "HAL Laboratory HALPST 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_XBOX_WVS, "Metal Arms WVS Header (XBOX)"},
{meta_NGC_WVS, "Metal Arms WVS Header (GameCube)"}, {meta_NGC_WVS, "Metal Arms WVS Header (GameCube)"},
{meta_XBOX_MATX, "assumed Matrix file by .matx extension"}, {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_VS, "Men in Black VS Header"},
{meta_DC_STR, "Sega Stream Asset Builder header"}, {meta_DC_STR, "Sega Stream Asset Builder header"},
{meta_DC_STR_V2, "variant of 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_XBOX_XVAS, "assumed TMNT file by .xvas extension"},
{meta_PS2_XA2, "Acclaim XA2 Header"}, {meta_PS2_XA2, "Acclaim XA2 Header"},
{meta_DC_IDVI, "Capcom IDVI header"}, {meta_DC_IDVI, "Capcom IDVI header"},
{meta_KRAW, "Geometry Wars: Galaxies KRAW header"},
{meta_NGC_YMF, "YMF DSP Header"}, {meta_NGC_YMF, "YMF DSP Header"},
{meta_PS2_CCC, "CCC Header"}, {meta_PS2_CCC, "CCC Header"},
{meta_PSX_FAG, "FAG Header"}, {meta_PSX_FAG, "FAG Header"},
@ -796,12 +801,12 @@ static const meta_info meta_info_list[] = {
{meta_S14, "Namco .S14 raw header"}, {meta_S14, "Namco .S14 raw header"},
{meta_SSS, "Namco .SSS raw header"}, {meta_SSS, "Namco .SSS raw header"},
{meta_PS2_GCM, "GCM 'MCG' 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_PS2_MSA, "Psyvariar -Complete Edition- MSA header"},
{meta_PC_SMP, "Ghostbusters .smp Header"}, {meta_PC_SMP, "Ghostbusters .smp Header"},
{meta_NGC_PDT, "PDT DSP header"}, {meta_NGC_PDT, "PDT DSP header"},
{meta_NGC_BO2, "Blood Omen 2 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_TK1, "Tekken TK5STRM1 Header"},
{meta_PS2_ADSC, "ADSC Header"}, {meta_PS2_ADSC, "ADSC Header"},
{meta_NGC_DSP_MPDS, "MPDS DSP 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_AL2, "Illwinter Game Design AL2 raw header"},
{meta_PC_AST, "Capcom AST (PC) header"}, {meta_PC_AST, "Capcom AST (PC) header"},
{meta_UBI_SB, "Ubisoft SBx header"}, {meta_UBI_SB, "Ubisoft SBx header"},
{meta_NAAC, "Namco NAAC header"},
#ifdef VGM_USE_VORBIS #ifdef VGM_USE_VORBIS
{meta_OGG_VORBIS, "Ogg Vorbis"}, {meta_OGG_VORBIS, "Ogg Vorbis"},

View File

@ -80,8 +80,8 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM *
case layout_xa_blocked: case layout_xa_blocked:
xa_block_update(vgmstream->next_block_offset,vgmstream); xa_block_update(vgmstream->next_block_offset,vgmstream);
break; break;
case layout_ea_blocked: case layout_blocked_ea_schl:
ea_schl_block_update(vgmstream->next_block_offset,vgmstream); block_update_ea_schl(vgmstream->next_block_offset,vgmstream);
break; break;
case layout_blocked_ea_1snh: case layout_blocked_ea_1snh:
block_update_ea_1snh(vgmstream->next_block_offset,vgmstream); 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: case layout_matx_blocked:
matx_block_update(vgmstream->next_block_offset,vgmstream); matx_block_update(vgmstream->next_block_offset,vgmstream);
break; break;
case layout_de2_blocked: case layout_blocked_dec:
de2_block_update(vgmstream->next_block_offset,vgmstream); block_update_dec(vgmstream->next_block_offset,vgmstream);
break; break;
case layout_emff_ps2_blocked: case layout_emff_ps2_blocked:
emff_ps2_block_update(vgmstream->next_block_offset,vgmstream); 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: case layout_filp_blocked:
filp_block_update(vgmstream->next_block_offset,vgmstream); filp_block_update(vgmstream->next_block_offset,vgmstream);
break; break;
case layout_ivaud_blocked: case layout_blocked_ivaud:
ivaud_block_update(vgmstream->next_block_offset,vgmstream); block_update_ivaud(vgmstream->next_block_offset,vgmstream);
break; break;
case layout_psx_mgav_blocked: case layout_psx_mgav_blocked:
psx_mgav_block_update(vgmstream->next_block_offset,vgmstream); 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: case layout_hwas_blocked:
hwas_block_update(vgmstream->next_block_offset,vgmstream); hwas_block_update(vgmstream->next_block_offset,vgmstream);
break; break;
case layout_ea_sns_blocked: case layout_blocked_ea_sns:
ea_sns_block_update(vgmstream->next_block_offset,vgmstream); block_update_ea_sns(vgmstream->next_block_offset,vgmstream);
break; break;
case layout_blocked_awc: case layout_blocked_awc:
block_update_awc(vgmstream->next_block_offset,vgmstream); block_update_awc(vgmstream->next_block_offset,vgmstream);

21
src/layout/blocked_dec.c Normal file
View File

@ -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;
}
}

View File

@ -3,7 +3,7 @@
#include "../vgmstream.h" #include "../vgmstream.h"
/* set up for the block at the given offset */ /* 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 i;
int new_schl = 0; int new_schl = 0;
STREAMFILE* streamFile = vgmstream->ch[0].streamfile; STREAMFILE* streamFile = vgmstream->ch[0].streamfile;

View File

@ -3,7 +3,7 @@
#include "../vgmstream.h" #include "../vgmstream.h"
/* EA "SNS "blocks (most common in .SNS) */ /* 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; STREAMFILE* streamFile = vgmstream->ch[0].streamfile;
uint32_t block_size, block_samples; uint32_t block_size, block_samples;
size_t file_size = get_streamfile_size(streamFile); size_t file_size = get_streamfile_size(streamFile);

View File

@ -2,7 +2,7 @@
#include "../vgmstream.h" #include "../vgmstream.h"
/* set up for the block at the given offset */ /* 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; int i;
off_t start_offset; off_t start_offset;
off_t interleave_size; off_t interleave_size;

View File

@ -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;i<vgmstream->channels;i++) {
vgmstream->ch[i].offset = vgmstream->current_block_offset + 8;
}
}

View File

@ -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 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); 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 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); 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 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); 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 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_awc(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_vgs(off_t block_offset, VGMSTREAM * vgmstream); void block_update_vgs(off_t block_offset, VGMSTREAM * vgmstream);

View File

@ -301,7 +301,7 @@
> >
</File> </File>
<File <File
RelativePath=".\meta\Cstr.c" RelativePath=".\meta\cstr.c"
> >
</File> </File>
<File <File
@ -325,7 +325,7 @@
> >
</File> </File>
<File <File
RelativePath=".\meta\de2.c" RelativePath=".\meta\dec.c"
> >
</File> </File>
<File <File
@ -514,6 +514,10 @@
RelativePath=".\meta\myspd.c" RelativePath=".\meta\myspd.c"
> >
</File> </File>
<File
RelativePath=".\meta\naac.c"
>
</File>
<File <File
RelativePath=".\meta\naomi_adpcm.c" RelativePath=".\meta\naomi_adpcm.c"
> >
@ -1603,15 +1607,15 @@
> >
</File> </File>
<File <File
RelativePath=".\layout\de2_blocked.c" RelativePath=".\layout\blocked_dec.c"
> >
</File> </File>
<File <File
RelativePath=".\layout\ea_block.c" RelativePath=".\layout\blocked_ea_schl.c"
> >
</File> </File>
<File <File
RelativePath=".\layout\ea_sns_blocked.c" RelativePath=".\layout\blocked_ea_sns.c"
> >
</File> </File>
<File <File
@ -1643,7 +1647,7 @@
> >
</File> </File>
<File <File
RelativePath=".\layout\ivaud_layout.c" RelativePath=".\layout\blocked_ivaud.c"
> >
</File> </File>
<File <File

View File

@ -210,13 +210,13 @@
<ClCompile Include="meta\brstm.c" /> <ClCompile Include="meta\brstm.c" />
<ClCompile Include="meta\btsnd.c" /> <ClCompile Include="meta\btsnd.c" />
<ClCompile Include="meta\capdsp.c" /> <ClCompile Include="meta\capdsp.c" />
<ClCompile Include="meta\Cstr.c" /> <ClCompile Include="meta\cstr.c" />
<ClCompile Include="meta\dc_asd.c" /> <ClCompile Include="meta\dc_asd.c" />
<ClCompile Include="meta\dc_dcsw_dcs.c" /> <ClCompile Include="meta\dc_dcsw_dcs.c" />
<ClCompile Include="meta\dc_idvi.c" /> <ClCompile Include="meta\dc_idvi.c" />
<ClCompile Include="meta\dc_kcey.c" /> <ClCompile Include="meta\dc_kcey.c" />
<ClCompile Include="meta\dc_str.c" /> <ClCompile Include="meta\dc_str.c" />
<ClCompile Include="meta\de2.c" /> <ClCompile Include="meta\dec.c" />
<ClCompile Include="meta\dmsg_segh.c" /> <ClCompile Include="meta\dmsg_segh.c" />
<ClCompile Include="meta\dsp_adx.c" /> <ClCompile Include="meta\dsp_adx.c" />
<ClCompile Include="meta\dsp_bdsp.c" /> <ClCompile Include="meta\dsp_bdsp.c" />
@ -259,6 +259,7 @@
<ClCompile Include="meta\musc.c" /> <ClCompile Include="meta\musc.c" />
<ClCompile Include="meta\musx.c" /> <ClCompile Include="meta\musx.c" />
<ClCompile Include="meta\myspd.c" /> <ClCompile Include="meta\myspd.c" />
<ClCompile Include="meta\naac.c" />
<ClCompile Include="meta\naomi_adpcm.c" /> <ClCompile Include="meta\naomi_adpcm.c" />
<ClCompile Include="meta\naomi_spsd.c" /> <ClCompile Include="meta\naomi_spsd.c" />
<ClCompile Include="meta\nds_hwas.c" /> <ClCompile Include="meta\nds_hwas.c" />
@ -474,9 +475,9 @@
<ClCompile Include="layout\blocked_ea_1snh.c" /> <ClCompile Include="layout\blocked_ea_1snh.c" />
<ClCompile Include="layout\blocked_vgs.c" /> <ClCompile Include="layout\blocked_vgs.c" />
<ClCompile Include="layout\caf_blocked.c" /> <ClCompile Include="layout\caf_blocked.c" />
<ClCompile Include="layout\de2_blocked.c" /> <ClCompile Include="layout\blocked_dec.c" />
<ClCompile Include="layout\ea_block.c" /> <ClCompile Include="layout\blocked_ea_schl.c" />
<ClCompile Include="layout\ea_sns_blocked.c" /> <ClCompile Include="layout\blocked_ea_sns.c" />
<ClCompile Include="layout\emff_blocked.c" /> <ClCompile Include="layout\emff_blocked.c" />
<ClCompile Include="layout\filp_blocked.c" /> <ClCompile Include="layout\filp_blocked.c" />
<ClCompile Include="layout\gsb_blocked.c" /> <ClCompile Include="layout\gsb_blocked.c" />
@ -484,7 +485,7 @@
<ClCompile Include="layout\ims_block.c" /> <ClCompile Include="layout\ims_block.c" />
<ClCompile Include="layout\interleave.c" /> <ClCompile Include="layout\interleave.c" />
<ClCompile Include="layout\interleave_byte.c" /> <ClCompile Include="layout\interleave_byte.c" />
<ClCompile Include="layout\ivaud_layout.c" /> <ClCompile Include="layout\blocked_ivaud.c" />
<ClCompile Include="layout\mus_acm_layout.c" /> <ClCompile Include="layout\mus_acm_layout.c" />
<ClCompile Include="layout\mxch_blocked.c" /> <ClCompile Include="layout\mxch_blocked.c" />
<ClCompile Include="layout\nolayout.c" /> <ClCompile Include="layout\nolayout.c" />

View File

@ -172,7 +172,7 @@
<ClCompile Include="meta\capdsp.c"> <ClCompile Include="meta\capdsp.c">
<Filter>meta\Source Files</Filter> <Filter>meta\Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="meta\Cstr.c"> <ClCompile Include="meta\cstr.c">
<Filter>meta\Source Files</Filter> <Filter>meta\Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="meta\dc_asd.c"> <ClCompile Include="meta\dc_asd.c">
@ -190,7 +190,7 @@
<ClCompile Include="meta\dc_str.c"> <ClCompile Include="meta\dc_str.c">
<Filter>meta\Source Files</Filter> <Filter>meta\Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="meta\de2.c"> <ClCompile Include="meta\dec.c">
<Filter>meta\Source Files</Filter> <Filter>meta\Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="meta\dmsg_segh.c"> <ClCompile Include="meta\dmsg_segh.c">
@ -295,6 +295,9 @@
<ClCompile Include="meta\myspd.c"> <ClCompile Include="meta\myspd.c">
<Filter>meta\Source Files</Filter> <Filter>meta\Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="meta\naac.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\naomi_adpcm.c"> <ClCompile Include="meta\naomi_adpcm.c">
<Filter>meta\Source Files</Filter> <Filter>meta\Source Files</Filter>
</ClCompile> </ClCompile>
@ -934,13 +937,13 @@
<ClCompile Include="layout\caf_blocked.c"> <ClCompile Include="layout\caf_blocked.c">
<Filter>layout\Source Files</Filter> <Filter>layout\Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="layout\de2_blocked.c"> <ClCompile Include="layout\blocked_dec.c">
<Filter>layout\Source Files</Filter> <Filter>layout\Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="layout\ea_block.c"> <ClCompile Include="layout\blocked_ea_schl.c">
<Filter>layout\Source Files</Filter> <Filter>layout\Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="layout\ea_sns_blocked.c"> <ClCompile Include="layout\blocked_ea_sns.c">
<Filter>layout\Source Files</Filter> <Filter>layout\Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="layout\emff_blocked.c"> <ClCompile Include="layout\emff_blocked.c">
@ -967,7 +970,7 @@
<ClCompile Include="layout\interleave_byte.c"> <ClCompile Include="layout\interleave_byte.c">
<Filter>layout\Source Files</Filter> <Filter>layout\Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="layout\ivaud_layout.c"> <ClCompile Include="layout\blocked_ivaud.c">
<Filter>layout\Source Files</Filter> <Filter>layout\Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="layout\mus_acm_layout.c"> <ClCompile Include="layout\mus_acm_layout.c">

View File

@ -61,7 +61,7 @@ VGMSTREAM * init_vgmstream_aix(STREAMFILE *streamFile) {
goto fail; goto fail;
sample_rate = read_32bitBE(stream_list_offset+8,streamFile); sample_rate = read_32bitBE(stream_list_offset+8,streamFile);
if (!check_sample_rate(sample_rate)) if (sample_rate < 300 || sample_rate > 96000)
goto fail; goto fail;
samples_in_segment = calloc(segment_count,sizeof(int32_t)); samples_in_segment = calloc(segment_count,sizeof(int32_t));

View File

@ -3,8 +3,7 @@
#include "../util.h" #include "../util.h"
/* .dsp w/ Cstr header, seen in Star Fox Assault and Donkey Konga */ /* .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; VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT]; char filename[PATH_LIMIT];

View File

@ -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;i<channel_count;i++) {
vgmstream->ch[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;
}

183
src/meta/dec.c Normal file
View File

@ -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;
}

View File

@ -250,7 +250,7 @@ static VGMSTREAM * init_vgmstream_ea_variable_header(STREAMFILE *streamFile, ea_
} }
} }
else { else {
vgmstream->layout_type = layout_ea_blocked; vgmstream->layout_type = layout_blocked_ea_schl;
} }
if (is_bnk) if (is_bnk)
@ -413,7 +413,7 @@ static VGMSTREAM * init_vgmstream_ea_variable_header(STREAMFILE *streamFile, ea_
} }
else { else {
/* setup first block to update offsets */ /* setup first block to update offsets */
ea_schl_block_update(start_offset,vgmstream); block_update_ea_schl(start_offset,vgmstream);
} }

View File

@ -58,7 +58,7 @@ VGMSTREAM * init_vgmstream_ea_schl_fixed(STREAMFILE *streamFile) {
vgmstream->meta_type = meta_EA_SCHL_fixed; vgmstream->meta_type = meta_EA_SCHL_fixed;
vgmstream->layout_type = layout_ea_blocked; vgmstream->layout_type = layout_blocked_ea_schl;
switch (ea.codec) { switch (ea.codec) {
case EA_CODEC_PCM: case EA_CODEC_PCM:
@ -80,7 +80,7 @@ VGMSTREAM * init_vgmstream_ea_schl_fixed(STREAMFILE *streamFile) {
goto fail; goto fail;
/* setup first block to update offsets */ /* setup first block to update offsets */
ea_schl_block_update(start_offset,vgmstream); block_update_ea_schl(start_offset,vgmstream);
return vgmstream; return vgmstream;

View File

@ -6,9 +6,9 @@
/* .SNU - from EA Redwood Shores/Visceral games (Dead Space, Dante's Inferno, The Godfather 2) */ /* .SNU - from EA Redwood Shores/Visceral games (Dead Space, Dante's Inferno, The Godfather 2) */
VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE *streamFile) { VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL; 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; 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; int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
@ -16,7 +16,7 @@ VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE *streamFile) {
if (!check_extensions(streamFile,"snu")) if (!check_extensions(streamFile,"snu"))
goto fail; 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) /* 0x00(1): related to sample rate? (03=48000)
* 0x01(1): flags/count? (when set has extra block data before start_offset) * 0x01(1): flags/count? (when set has extra block data before start_offset)
* 0x02(1): always 0? * 0x02(1): always 0?
@ -32,32 +32,48 @@ VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE *streamFile) {
read_32bit = read_32bitLE; 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) { /* Beyond is the newest EA header (from EAAudioCore library) still generated by sx.exe.
VGM_LOG("EA SNS: unknown flag\n"); * 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; goto fail;
} }
#if 0 /* & 0x40: stream asset?, 0x20: full loop?, 0x00: RAM asset?, 0x01: loop? */
//todo not working ok with blocks in XAS if (flags != 0x60 && flags != 0x40) {
//todo check if EA-XMA loops (Dante's Inferno doesn't) VGM_LOG("EA SNS/SPS: unknown flag 0x%02x\n", flags);
if (flags & 0x60) { /* full loop, seen in ambient tracks */ }
/* full loop seen in Dead Space ambient tracks */
if (flags == 0x60) {
VGM_LOG("flg=%x\n",flags);
loop_flag = 1; loop_flag = 1;
loop_start = 0; loop_start = 0;
loop_end = num_samples; loop_end = num_samples;
} }
#endif
//channel_count = (channel_config >> 2) + 1; //todo test /* accepted channel configs only seem to be mono/stereo/quad/5.1/7.1 */
/* 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? */ //channel_count = ((channel_config >> 2) & 0xf) + 1;
switch(channel_config) { switch(channel_config) {
case 0x00: channel_count = 1; break; case 0x00: channel_count = 1; break;
case 0x04: channel_count = 2; 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 0x14: channel_count = 6; break;
case 0x1c: channel_count = 8; break; case 0x1c: channel_count = 8; break;
default: 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; goto fail;
} }
@ -81,15 +97,16 @@ VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE *streamFile) {
vgmstream->meta_type = meta_EA_SNU; vgmstream->meta_type = meta_EA_SNU;
/* EA decoder list and known internal FourCCs */
switch(codec) { switch(codec) {
case 0x04: /* "Xas1": EA-XAS (Dead Space PC/PS3) */ case 0x04: /* "Xas1": EA-XAS (Dead Space PC/PS3) */
vgmstream->coding_type = coding_EA_XAS; vgmstream->coding_type = coding_EA_XAS;
vgmstream->layout_type = layout_ea_sns_blocked; vgmstream->layout_type = layout_blocked_ea_sns;
break; break;
#if 0 #if 0
#ifdef VGM_USE_MPEG #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; mpeg_custom_config cfg;
off_t mpeg_start_offset = start_offset + 0x08; 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); 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; if (!vgmstream->codec_data) goto fail;
vgmstream->layout_type = layout_ea_sns_blocked; vgmstream->layout_type = layout_blocked_ea_sns;
break; break;
} }
#endif #endif
@ -133,19 +150,23 @@ VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE *streamFile) {
break; break;
} }
#endif #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 0x05: /* "EL31": EALayer3 v1 b (with PCM blocks in normal EA-frames?) */
case 0x06: /* "EL32P": EALayer3 v2 "P" */ case 0x06: /* "L32P": EALayer3 v2 "P" */
case 0x09: /* EASpeex? */
case 0x0c: /* EAOpus? */ case 0x08: /* ? */
case 0x0e: /* XAS variant? */ case 0x09: /* EASpeex? "Esp0" (libspeex variant) */
case 0x0f: /* EALayer3 variant? */ case 0x0a: /* EATrax (ATRAC9 variant, deflated frames) */
/* also 0x1n variations, used in other headers */ case 0x0b: /* ? */
case 0x0c: /* EAOpus (inside each SNS/SPS block is 16b frame size + Opus standard? packet) */
case 0x0d: /* ? */
case 0x0e: /* ? */
case 0x0f: /* ? */
default: default:
VGM_LOG("EA SNU: unknown codec 0x%02x\n", codec); VGM_LOG("EA SNS/SPS: unknown codec 0x%02x\n", codec);
goto fail; goto fail;
} }
@ -154,8 +175,8 @@ VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE *streamFile) {
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail; goto fail;
if (vgmstream->layout_type == layout_ea_sns_blocked) if (vgmstream->layout_type == layout_blocked_ea_sns)
ea_sns_block_update(start_offset, vgmstream); block_update_ea_sns(start_offset, vgmstream);
return vgmstream; return vgmstream;

View File

@ -220,13 +220,13 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) {
for (i=0;i<vgmstream->channels;i++) { for (i=0;i<vgmstream->channels;i++) {
int16_t (*read_16bit)(off_t , STREAMFILE*) = genh.coef_big_endian ? read_16bitBE : read_16bitLE; int16_t (*read_16bit)(off_t , STREAMFILE*) = genh.coef_big_endian ? read_16bitBE : read_16bitLE;
/* normal/split coefs */ /* normal/split coefs bit flag */
if ((genh.coef_type & 1) == 0) { /* bit 0 - split coefs (2 arrays) */ if ((genh.coef_type & 1) == 0) { /* not set: normal coefs, all 16 interleaved into one array */
for (j=0;j<16;j++) { for (j=0;j<16;j++) {
vgmstream->ch[i].adpcm_coef[j] = read_16bit(genh.coef[i]+j*2,streamFile); 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++) { 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]=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); 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); genh->coef_interleave_type = read_32bitLE(0x2C,streamFile);
/* DSP coefficient variants */ /* DSP coefficient variants */
/* bit 0 - split coefs (2 arrays) */ /* bit 0 flag - split coefs (2 arrays) */
/* bit 1 - little endian coefs */ /* bit 1 flag - little endian coefs (for some 3DS) */
genh->coef_type = read_32bitLE(0x30,streamFile); genh->coef_type = read_32bitLE(0x30,streamFile);
genh->coef_big_endian = ((genh->coef_type & 2) == 0); genh->coef_big_endian = ((genh->coef_type & 2) == 0);

View File

@ -38,7 +38,7 @@ VGMSTREAM * init_vgmstream_ivaud(STREAMFILE *streamFile) {
vgmstream->sample_rate = read_32bitLE(block_table_offset + 0x04,streamFile); vgmstream->sample_rate = read_32bitLE(block_table_offset + 0x04,streamFile);
vgmstream->coding_type = coding_IMA_int; vgmstream->coding_type = coding_IMA_int;
vgmstream->layout_type = layout_ivaud_blocked; vgmstream->layout_type = layout_blocked_ivaud;
vgmstream->meta_type = meta_PC_IVAUD; vgmstream->meta_type = meta_PC_IVAUD;
/* open the file for reading */ /* open the file for reading */
@ -57,7 +57,7 @@ VGMSTREAM * init_vgmstream_ivaud(STREAMFILE *streamFile) {
// to avoid troubles with "extra" samples // to avoid troubles with "extra" samples
vgmstream->num_samples=((read_32bitLE(0x60,streamFile)/2)*2); vgmstream->num_samples=((read_32bitLE(0x60,streamFile)/2)*2);
ivaud_block_update(start_offset,vgmstream); block_update_ivaud(start_offset,vgmstream);
return vgmstream; return vgmstream;

View File

@ -15,7 +15,7 @@ VGMSTREAM * init_vgmstream_ast(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_brstm(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); 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_xbox_matx(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_de2(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_dec(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_vs(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_pc_ast(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_naac(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ubi_sb(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_ubi_sb(STREAMFILE * streamFile);
#endif /*_META_H*/ #endif /*_META_H*/

View File

@ -125,7 +125,7 @@ VGMSTREAM * init_vgmstream_mus_acm(STREAMFILE *streamFile) {
if (strcasecmp("mus",filename_extension(filename))) goto fail; if (strcasecmp("mus",filename_extension(filename))) goto fail;
/* read file name base */ /* 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); mus_offset, streamFile, &whole_line_read);
if (!whole_line_read) goto fail; if (!whole_line_read) goto fail;
mus_offset += line_bytes; mus_offset += line_bytes;
@ -140,7 +140,7 @@ VGMSTREAM * init_vgmstream_mus_acm(STREAMFILE *streamFile) {
/*printf("name base: %s\n",name_base);*/ /*printf("name base: %s\n",name_base);*/
/* read track entry count */ /* 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); mus_offset, streamFile, &whole_line_read);
if (!whole_line_read) goto fail; if (!whole_line_read) goto fail;
if (line_buffer[0] == '\0') goto fail; if (line_buffer[0] == '\0') goto fail;
@ -184,7 +184,7 @@ VGMSTREAM * init_vgmstream_mus_acm(STREAMFILE *streamFile) {
{ {
int fields_matched; int fields_matched;
line_bytes = 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); mus_offset, streamFile, &whole_line_read);
if (!whole_line_read) goto fail; if (!whole_line_read) goto fail;
mus_offset += line_bytes; mus_offset += line_bytes;

66
src/meta/naac.c Normal file
View File

@ -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;
}

View File

@ -1,63 +1,48 @@
#include "meta.h" #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 * init_vgmstream_ps2_smpl(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL; VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t start_offset; off_t start_offset;
int loop_flag, channel_count;
size_t channel_size;
int loop_flag; /* check extension (.v0: left channel, .v1: right channel, .smpl: header id) */
int channel_count; if ( !check_extensions(streamFile,"v0,v1,smpl") )
goto fail;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("smpl",filename_extension(filename))) goto fail;
/* check header */ /* check header */
if (read_32bitBE(0x00,streamFile) != 0x534D504C) /* "SMPL" */ if (read_32bitBE(0x00,streamFile) != 0x534D504C) /* "SMPL" */
goto fail; goto fail;
loop_flag = 1;
channel_count = 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); vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail; if (!vgmstream) goto fail;
/* fill in the vital statistics */
start_offset = 0x40;
vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitBE(0x10,streamFile); vgmstream->sample_rate = read_32bitBE(0x10,streamFile);
vgmstream->coding_type = coding_PSX_badflags; vgmstream->num_samples = ps_bytes_to_samples(channel_size*channel_count, channel_count);
vgmstream->num_samples = read_32bitBE(0xc,streamFile)*56/32;
if (loop_flag) {
vgmstream->loop_start_sample = read_32bitLE(0x30,streamFile); vgmstream->loop_start_sample = read_32bitLE(0x30,streamFile);
vgmstream->loop_end_sample = vgmstream->num_samples; vgmstream->loop_end_sample = vgmstream->num_samples;
}
vgmstream->layout_type = layout_none;
vgmstream->meta_type = meta_PS2_SMPL; 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 */ /* open the file for reading */
{ if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
int i; goto fail;
STREAMFILE * file;
file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!file) goto fail;
for (i=0;i<channel_count;i++) {
vgmstream->ch[i].streamfile = file;
vgmstream->ch[i].channel_start_offset=
vgmstream->ch[i].offset=start_offset+
vgmstream->interleave_block_size*i;
}
}
return vgmstream; return vgmstream;
/* clean up anything we may have opened */
fail: fail:
if (vgmstream) close_vgmstream(vgmstream); close_vgmstream(vgmstream);
return NULL; return NULL;
} }

View File

@ -54,7 +54,7 @@ VGMSTREAM * init_vgmstream_sli_ogg(STREAMFILE *streamFile) {
while ((loop_start == -1 || loop_length == -1) && sli_offset < get_streamfile_size(streamFile)) { while ((loop_start == -1 || loop_length == -1) && sli_offset < get_streamfile_size(streamFile)) {
char *endptr; char *endptr;
char *foundptr; 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 (!done) goto fail;
if (!memcmp("LoopStart=",linebuffer,10) && linebuffer[10]!='\0') { if (!memcmp("LoopStart=",linebuffer,10) && linebuffer[10]!='\0') {

View File

@ -3,7 +3,7 @@
#include "../layout/layout.h" #include "../layout/layout.h"
#include "../util.h" #include "../util.h"
#define TXTH_LINE_MAX 0x2000 #define TXT_LINE_MAX 0x2000
/* known TXTH types */ /* known TXTH types */
typedef enum { typedef enum {
@ -83,7 +83,7 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) {
int i, j; int i, j;
/* no need for ID or ext checks -- if a .TXTH exists all is good /* 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); streamText = open_txth(streamFile);
if (!streamText) goto fail; if (!streamText) goto fail;
@ -401,44 +401,28 @@ fail:
/* Simple text parser of "key = value" lines. /* Simple text parser of "key = value" lines.
* The code is meh and error handling not exactly the best. */ * The code is meh and error handling not exactly the best. */
static int parse_txth(STREAMFILE * streamFile, STREAMFILE * streamText, txth_header * txth) { 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); off_t file_size = get_streamfile_size(streamText);
txth->data_size = get_streamfile_size(streamFile); /* for later use */ txth->data_size = get_streamfile_size(streamFile); /* for later use */
/* skip BOM if needed */ /* skip BOM if needed */
if (read_16bitLE(0x00, streamText) == 0xFFFE || read_16bitLE(0x00, streamText) == 0xFEFF) if (read_16bitLE(0x00, streamText) == 0xFFFE || read_16bitLE(0x00, streamText) == 0xFEFF)
off = 0x02; txt_offset = 0x02;
/* read lines */ /* read lines */
while (off < file_size) { while (txt_offset < file_size) {
char line[TXTH_LINE_MAX]; char line[TXT_LINE_MAX] = {0};
char key[TXTH_LINE_MAX]; char key[TXT_LINE_MAX] = {0}, val[TXT_LINE_MAX] = {0}; /* at least as big as a line to avoid overflows (I hope) */
char val[TXTH_LINE_MAX]; /* at least as big as a line to avoid overflows (I hope) */ int ok, bytes_read, line_done;
int ok;
off_t line_start = off, line_end = 0;
line[0] = key[0] = val[0] = 0;
/* find line end */ bytes_read = get_streamfile_text_line(TXT_LINE_MAX,line, txt_offset,streamText, &line_done);
while (line_end == 0 && off - line_start < TXTH_LINE_MAX) { if (!line_done) goto fail;
char c = (char)read_8bit(off, streamText);
if (c == '\n')
line_end = off;
else if (off >= file_size)
line_end = off-1;
off++; txt_offset += bytes_read;
}
if (line_end == 0)
goto fail; /* bad file / line too long */
/* get key/val (ignores lead/trail spaces, stops at space/comment/separator) */ /* 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); 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) */ if (ok != 2) /* ignore line if no key=val (comment or garbage) */
continue; continue;

View File

@ -22,9 +22,6 @@ typedef struct {
uint8_t * buffer; /* data buffer */ uint8_t * buffer; /* data buffer */
size_t buffersize; /* max buffer size */ size_t buffersize; /* max buffer size */
size_t filesize; /* cached file size (max offset) */ size_t filesize; /* cached file size (max offset) */
#ifdef VGM_DEBUG_OUTPUT
int error_notified;
#endif
#ifdef PROFILE_STREAMFILE #ifdef PROFILE_STREAMFILE
size_t bytes_read; size_t bytes_read;
int error_count; 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 */ /* request outside file: ignore to avoid seek/read */
if (offset > streamfile->filesize) { if (offset > streamfile->filesize) {
streamfile->offset = streamfile->filesize; streamfile->offset = streamfile->filesize;
VGM_LOG_ONCE("ERROR: reading over filesize 0x%x @ 0x%lx + 0x%x (buggy meta?)\n", streamfile->filesize, offset, length);
#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
#if STREAMFILE_IGNORE_EOF #if STREAMFILE_IGNORE_EOF
memset(dest,0,length); /* dest is already shifted */ 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() */ /* request outside file: ignore to avoid seek/read in read_the_rest() */
if (offset > streamfile->filesize) { if (offset > streamfile->filesize) {
streamfile->offset = streamfile->filesize; streamfile->offset = streamfile->filesize;
VGM_LOG_ONCE("ERROR: offset over filesize 0x%x @ 0x%lx + 0x%x (buggy meta?)\n", streamfile->filesize, offset, length);
#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
#if STREAMFILE_IGNORE_EOF #if STREAMFILE_IGNORE_EOF
memset(dest,0,length); memset(dest,0,length);
@ -298,37 +283,32 @@ STREAMFILE * open_stdio_streamfile_by_file(FILE * file, const char * filename) {
/* **************************************************** */ /* **************************************************** */
/* Read a line into dst. The source files are MS-DOS style, /* Read a line into dst. The source files are lines separated by CRLF (Windows) / LF (Unux) / CR (Mac).
* separated (not terminated) by CRLF. Return 1 if the full line was * The line will be null-terminated and CR/LF removed if found.
* 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. * Returns the number of bytes read (including CR/LF), note that this is not the string length.
* Return the number of bytes read (including CRLF line ending). Note that * line_done_ptr is set to 1 if the complete line was read into dst; NULL can be passed to ignore.
* 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.
*/ */
size_t get_streamfile_dos_line(int dst_length, char * dst, off_t offset, size_t get_streamfile_text_line(int dst_length, char * dst, off_t offset, STREAMFILE * streamfile, int *line_done_ptr) {
STREAMFILE * infile, int *line_done_ptr)
{
int i; int i;
off_t file_length = get_streamfile_size(infile); off_t file_length = get_streamfile_size(streamfile);
/* how many bytes over those put in the buffer were read */ int extra_bytes = 0; /* how many bytes over those put in the buffer were read */
int extra_bytes = 0;
if (line_done_ptr) *line_done_ptr = 0; if (line_done_ptr) *line_done_ptr = 0;
for (i=0;i<dst_length-1 && offset+i < file_length;i++) for (i = 0; i < dst_length-1 && offset+i < file_length; i++) {
{ char in_char = read_8bit(offset+i,streamfile);
char in_char = read_8bit(offset+i,infile);
/* check for end of line */ /* check for end of line */
if (in_char == 0x0d && if (in_char == 0x0d && read_8bit(offset+i+1,streamfile) == 0x0a) { /* CRLF */
read_8bit(offset+i+1,infile) == 0x0a)
{
extra_bytes = 2; extra_bytes = 2;
if (line_done_ptr) *line_done_ptr = 1; if (line_done_ptr) *line_done_ptr = 1;
break; break;
} }
else if (in_char == 0x0d || in_char == 0x0a) { /* CR or LF */
extra_bytes = 1;
if (line_done_ptr) *line_done_ptr = 1;
break;
}
dst[i] = in_char; dst[i] = in_char;
} }
@ -337,19 +317,20 @@ size_t get_streamfile_dos_line(int dst_length, char * dst, off_t offset,
/* did we fill the buffer? */ /* did we fill the buffer? */
if (i == dst_length) { if (i == dst_length) {
char in_char = read_8bit(offset+i,streamfile);
/* did the bytes we missed just happen to be the end of the line? */ /* did the bytes we missed just happen to be the end of the line? */
if (read_8bit(offset+i,infile) == 0x0d && if (in_char == 0x0d && read_8bit(offset+i+1,streamfile) == 0x0a) { /* CRLF */
read_8bit(offset+i+1,infile) == 0x0a)
{
extra_bytes = 2; extra_bytes = 2;
/* if so be proud! */ if (line_done_ptr) *line_done_ptr = 1;
}
else if (in_char == 0x0d || in_char == 0x0a) { /* CR or LF */
extra_bytes = 1;
if (line_done_ptr) *line_done_ptr = 1; if (line_done_ptr) *line_done_ptr = 1;
} }
} }
/* did we hit the file end? */ /* did we hit the file end? */
if (offset+i == file_length) if (offset+i == file_length) {
{
/* then we did in fact finish reading the last line */ /* then we did in fact finish reading the last line */
if (line_done_ptr) *line_done_ptr = 1; if (line_done_ptr) *line_done_ptr = 1;
} }
@ -380,9 +361,7 @@ fail:
return 0; return 0;
} }
/** /* Opens an stream using the base streamFile name plus a new extension (ex. for headers in a separate file) */
* Opens an stream using the base streamFile name plus a new extension (ex. for headers in a separate file)
*/
STREAMFILE * open_stream_ext(STREAMFILE *streamFile, const char * ext) { STREAMFILE * open_stream_ext(STREAMFILE *streamFile, const char * ext) {
char filename_ext[PATH_LIMIT]; char filename_ext[PATH_LIMIT];
@ -392,7 +371,7 @@ STREAMFILE * open_stream_ext(STREAMFILE *streamFile, const char * ext) {
return streamFile->open(streamFile,filename_ext,STREAMFILE_DEFAULT_BUFFER_SIZE); return streamFile->open(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) { STREAMFILE * open_stream_name(STREAMFILE *streamFile, const char * name) {
char foldername[PATH_LIMIT]; char foldername[PATH_LIMIT];
char filename[PATH_LIMIT]; char filename[PATH_LIMIT];

View File

@ -156,7 +156,7 @@ static inline int8_t read_8bit(off_t offset, STREAMFILE * streamfile) {
/* various STREAMFILE helpers functions */ /* 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_ext(STREAMFILE *streamFile, const char * ext);
STREAMFILE * open_stream_name(STREAMFILE *streamFile, const char * ext); STREAMFILE * open_stream_name(STREAMFILE *streamFile, const char * ext);

View File

@ -2,10 +2,6 @@
#include "util.h" #include "util.h"
#include "streamtypes.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 * filename_extension(const char * filename) {
const char * ext; const char * ext;

View File

@ -61,9 +61,6 @@ static inline int get_low_nibble_signed(uint8_t n) {
return nibble_to_int[n&0xf]; 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 /* 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 * 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. /* 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 #ifdef VGM_DEBUG_OUTPUT
/* equivalent to printf when condition is true */ /* equivalent to printf when condition is true */
#define VGM_ASSERT(condition, ...) \ #define VGM_ASSERT(condition, ...) \
do { if (condition) printf(__VA_ARGS__); } while (0) 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 */ /* equivalent to printf */
#define VGM_LOG(...) \ #define VGM_LOG(...) \
do { printf(__VA_ARGS__); } while (0) 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 */ /* prints file/line/func */
#define VGM_LOGF() \ #define VGM_LOGF() \
do { printf("%s:%i '%s'\n", __FILE__, __LINE__, __func__); } while (0) 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_ASSERT(condition, ...) /* nothing */
#define VGM_LOG(...) /* nothing */ #define VGM_LOG(...) /* nothing */
#define VGM_LOG_ONCE(...) /* nothing */
#define VGM_LOGF() /* nothing */ #define VGM_LOGF() /* nothing */
#define VGM_LOGT() /* nothing */ #define VGM_LOGT() /* nothing */
#define VGM_LOGB(buf, buf_size, bytes_per_line) /* nothing */ #define VGM_LOGB(buf, buf_size, bytes_per_line) /* nothing */
#endif/*VGM_DEBUG_OUTPUT*/ #endif/*VGM_DEBUG_OUTPUT*/
#endif #endif

View File

@ -10,16 +10,11 @@
#include "layout/layout.h" #include "layout/layout.h"
#include "coding/coding.h" #include "coding/coding.h"
/* See if there is a second file which may be the second channel, given static void try_dual_file_stereo(VGMSTREAM * opened_vgmstream, STREAMFILE *streamFile, VGMSTREAM* (*init_vgmstream_function)(STREAMFILE*));
* 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);
/* /* List of functions that will recognize files */
* List of functions that will recognize files. VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
*/
VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = {
init_vgmstream_adx, init_vgmstream_adx,
init_vgmstream_brstm, init_vgmstream_brstm,
init_vgmstream_bfwav, init_vgmstream_bfwav,
@ -37,7 +32,7 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = {
init_vgmstream_ngc_dsp_std, init_vgmstream_ngc_dsp_std,
init_vgmstream_ngc_mdsp_std, init_vgmstream_ngc_mdsp_std,
init_vgmstream_ngc_dsp_csmp, init_vgmstream_ngc_dsp_csmp,
init_vgmstream_Cstr, init_vgmstream_cstr,
init_vgmstream_gcsw, init_vgmstream_gcsw,
init_vgmstream_ps2_ads, init_vgmstream_ps2_ads,
init_vgmstream_ps2_npsf, init_vgmstream_ps2_npsf,
@ -138,7 +133,7 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = {
init_vgmstream_dc_str, init_vgmstream_dc_str,
init_vgmstream_dc_str_v2, init_vgmstream_dc_str_v2,
init_vgmstream_xbox_matx, init_vgmstream_xbox_matx,
init_vgmstream_de2, init_vgmstream_dec,
init_vgmstream_vs, init_vgmstream_vs,
init_vgmstream_dc_str, init_vgmstream_dc_str,
init_vgmstream_dc_str_v2, init_vgmstream_dc_str_v2,
@ -368,6 +363,7 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = {
init_vgmstream_nsw_opus, init_vgmstream_nsw_opus,
init_vgmstream_pc_al2, init_vgmstream_pc_al2,
init_vgmstream_pc_ast, init_vgmstream_pc_ast,
init_vgmstream_naac,
init_vgmstream_ubi_sb, init_vgmstream_ubi_sb,
init_vgmstream_txth, /* should go at the end (lower priority) */ init_vgmstream_txth, /* should go at the end (lower priority) */
@ -378,19 +374,19 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = {
/* internal version with all parameters */ /* 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; int i, fcns_size;
if (!streamFile) if (!streamFile)
return NULL; 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 */ /* try a series of formats, see which works */
for (i=0; i < fcns_size; i++) { for (i=0; i < fcns_size; i++) {
/* call init function and see if valid VGMSTREAM was returned */ /* call init function and see if valid VGMSTREAM was returned */
VGMSTREAM * vgmstream = (init_vgmstream_fcns[i])(streamFile); VGMSTREAM * vgmstream = (init_vgmstream_functions[i])(streamFile);
if (vgmstream) { if (!vgmstream)
/* these are little hacky checks */ continue;
/* fail if there is nothing to play (without this check vgmstream can generate empty files) */ /* fail if there is nothing to play (without this check vgmstream can generate empty files) */
if (vgmstream->num_samples <= 0) { if (vgmstream->num_samples <= 0) {
@ -399,8 +395,8 @@ static VGMSTREAM * init_vgmstream_internal(STREAMFILE *streamFile, int do_dfs) {
continue; continue;
} }
/* everything should have a reasonable sample rate (a verification of the metadata) */ /* everything should have a reasonable sample rate (300 is Wwise min) */
if (!check_sample_rate(vgmstream->sample_rate)) { if (vgmstream->sample_rate < 300 || vgmstream->sample_rate > 96000) {
VGM_LOG("VGMSTREAM: wrong sample rate (sr=%i)\n", vgmstream->sample_rate); VGM_LOG("VGMSTREAM: wrong sample rate (sr=%i)\n", vgmstream->sample_rate);
close_vgmstream(vgmstream); close_vgmstream(vgmstream);
continue; continue;
@ -416,11 +412,12 @@ static VGMSTREAM * init_vgmstream_internal(STREAMFILE *streamFile, int do_dfs) {
} }
} }
/* dual file stereo */ /* test if candidate for dual stereo */
if (do_dfs && ( if (vgmstream->channels == 1 && (
(vgmstream->meta_type == meta_DSP_STD) || (vgmstream->meta_type == meta_DSP_STD) ||
(vgmstream->meta_type == meta_PS2_VAGp) || (vgmstream->meta_type == meta_PS2_VAGp) ||
(vgmstream->meta_type == meta_GENH) || (vgmstream->meta_type == meta_GENH) ||
(vgmstream->meta_type == meta_TXTH) ||
(vgmstream->meta_type == meta_KRAW) || (vgmstream->meta_type == meta_KRAW) ||
(vgmstream->meta_type == meta_PS2_MIB) || (vgmstream->meta_type == meta_PS2_MIB) ||
(vgmstream->meta_type == meta_NGC_LPS) || (vgmstream->meta_type == meta_NGC_LPS) ||
@ -432,10 +429,26 @@ static VGMSTREAM * init_vgmstream_internal(STREAMFILE *streamFile, int do_dfs) {
(vgmstream->meta_type == meta_SPT_SPD) || (vgmstream->meta_type == meta_SPT_SPD) ||
(vgmstream->meta_type == meta_EB_SFX) || (vgmstream->meta_type == meta_EB_SFX) ||
(vgmstream->meta_type == meta_CWAV) (vgmstream->meta_type == meta_CWAV)
) && vgmstream->channels == 1) { )) {
try_dual_file_stereo(vgmstream, streamFile); 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 #ifdef VGM_USE_FFMPEG
/* check FFmpeg streams here, for lack of a better place */ /* check FFmpeg streams here, for lack of a better place */
if (vgmstream->coding_type == coding_FFmpeg) { if (vgmstream->coding_type == coding_FFmpeg) {
@ -450,15 +463,13 @@ static VGMSTREAM * init_vgmstream_internal(STREAMFILE *streamFile, int do_dfs) {
vgmstream->stream_index = streamFile->stream_index; vgmstream->stream_index = streamFile->stream_index;
/* save start things so we can restart for seeking */ /* save start things so we can restart for seeking */
/* copy the channels */
memcpy(vgmstream->start_ch,vgmstream->ch,sizeof(VGMSTREAMCHANNEL)*vgmstream->channels); memcpy(vgmstream->start_ch,vgmstream->ch,sizeof(VGMSTREAMCHANNEL)*vgmstream->channels);
/* copy the whole VGMSTREAM */
memcpy(vgmstream->start_vgmstream,vgmstream,sizeof(VGMSTREAM)); memcpy(vgmstream->start_vgmstream,vgmstream,sizeof(VGMSTREAM));
return vgmstream; return vgmstream;
} }
}
/* not supported */
return NULL; return NULL;
} }
@ -474,7 +485,7 @@ VGMSTREAM * init_vgmstream(const char * const filename) {
} }
VGMSTREAM * init_vgmstream_from_STREAMFILE(STREAMFILE *streamFile) { 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. /* 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_ast_blocked:
case layout_halpst_blocked: case layout_halpst_blocked:
case layout_xa_blocked: case layout_xa_blocked:
case layout_ea_blocked: case layout_blocked_ea_schl:
case layout_blocked_ea_1snh: case layout_blocked_ea_1snh:
case layout_caf_blocked: case layout_caf_blocked:
case layout_wsi_blocked: case layout_wsi_blocked:
case layout_str_snds_blocked: case layout_str_snds_blocked:
case layout_ws_aud_blocked: case layout_ws_aud_blocked:
case layout_matx_blocked: case layout_matx_blocked:
case layout_de2_blocked: case layout_blocked_dec:
case layout_vs_blocked: case layout_vs_blocked:
case layout_emff_ps2_blocked: case layout_emff_ps2_blocked:
case layout_emff_ngc_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_xvas_blocked:
case layout_thp_blocked: case layout_thp_blocked:
case layout_filp_blocked: case layout_filp_blocked:
case layout_ivaud_blocked: case layout_blocked_ivaud:
case layout_psx_mgav_blocked: case layout_psx_mgav_blocked:
case layout_ps2_adm_blocked: case layout_ps2_adm_blocked:
case layout_dsp_bdsp_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_ps2_strlr_blocked:
case layout_rws_blocked: case layout_rws_blocked:
case layout_hwas_blocked: case layout_hwas_blocked:
case layout_ea_sns_blocked: case layout_blocked_ea_sns:
case layout_blocked_awc: case layout_blocked_awc:
case layout_blocked_vgs: case layout_blocked_vgs:
render_vgmstream_blocked(buffer,sample_count,vgmstream); render_vgmstream_blocked(buffer,sample_count,vgmstream);
@ -1960,6 +1971,7 @@ int vgmstream_do_loop(VGMSTREAM * vgmstream) {
vgmstream->current_sample = vgmstream->loop_sample; vgmstream->current_sample = vgmstream->loop_sample;
vgmstream->samples_into_block = vgmstream->loop_samples_into_block; vgmstream->samples_into_block = vgmstream->loop_samples_into_block;
vgmstream->current_block_size = vgmstream->loop_block_size; 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->current_block_offset = vgmstream->loop_block_offset;
vgmstream->next_block_offset = vgmstream->loop_next_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_sample = vgmstream->current_sample;
vgmstream->loop_samples_into_block = vgmstream->samples_into_block; vgmstream->loop_samples_into_block = vgmstream->samples_into_block;
vgmstream->loop_block_size = vgmstream->current_block_size; 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_block_offset = vgmstream->current_block_offset;
vgmstream->loop_next_block_offset = vgmstream->next_block_offset; vgmstream->loop_next_block_offset = vgmstream->next_block_offset;
vgmstream->hit_loop = 1; vgmstream->hit_loop = 1;
@ -2136,104 +2149,108 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
} }
} }
/* 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 */ /* filename search pairs for dual file stereo */
const char * const dfs_pairs[][2] = { static const char * const dfs_pairs[][2] = {
{"L","R"}, {"L","R"},
{"l","r"}, {"l","r"},
{"_0","_1"},
{"left","right"}, {"left","right"},
{"Left","Right"}, {"Left","Right"},
{".V0",".V1"},
{"_0","_1"}, //unneeded?
}; };
#define DFS_PAIR_COUNT (sizeof(dfs_pairs)/sizeof(dfs_pairs[0])) char new_filename[PATH_LIMIT];
static void try_dual_file_stereo(VGMSTREAM * opened_stream, STREAMFILE *streamFile) {
char filename[PATH_LIMIT];
char filename2[PATH_LIMIT];
char * ext; char * ext;
int dfs_name= -1; /*-1=no stereo, 0=opened_stream is left, 1=opened_stream is right */ int dfs_pair = -1; /* -1=no stereo, 0=opened_vgmstream is left, 1=opened_vgmstream is right */
VGMSTREAM * new_stream = NULL; VGMSTREAM *new_vgmstream = NULL;
STREAMFILE *dual_stream = NULL; STREAMFILE *dual_streamFile = NULL;
int i,j; int i,j, dfs_pair_count;
if (opened_stream->channels != 1) return; if (opened_vgmstream->channels != 1)
return;
streamFile->get_name(streamFile,filename,sizeof(filename));
/* vgmstream's layout stuff currently assumes a single file */ /* vgmstream's layout stuff currently assumes a single file */
// fastelbja : no need ... this one works ok with dual 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 */ streamFile->get_name(streamFile,new_filename,sizeof(new_filename));
if (strlen(filename)<2) return; if (strlen(new_filename)<2) return; /* we need at least a base and a name ending to replace */
strcpy(filename2,filename); ext = (char *)filename_extension(new_filename);
if (ext-new_filename >= 1 && ext[-1]=='.') ext--; /* including "." */
/* look relative to the extension; */ /* find pair from base name and modify new_filename with the opposite */
ext = (char *)filename_extension(filename2); 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]);
/* we treat the . as part of the extension */ /* if suffix matches copy opposite to ext pointer (thus to new_filename) */
if (ext-filename2 >= 1 && ext[-1]=='.') ext--; if (this_suffix[0] == '.' && strlen(ext) == this_suffix_len) { /* dual extension (ex. Homura PS2) */
if ( !memcmp(ext,this_suffix,this_suffix_len) ) {
for (i=0; dfs_name==-1 && i<DFS_PAIR_COUNT; i++) { dfs_pair = j;
for (j=0; dfs_name==-1 && j<2; j++) { memcpy (ext, other_suffix,other_suffix_len); /* overwrite with new extension */
/* find a postfix on the name */
if (!memcmp(ext-strlen(dfs_pairs[i][j]),
dfs_pairs[i][j],
strlen(dfs_pairs[i][j]))) {
int other_name=j^1;
int moveby;
dfs_name=j;
/* move the extension */
moveby = strlen(dfs_pairs[i][other_name]) -
strlen(dfs_pairs[i][dfs_name]);
memmove(ext+moveby,ext,strlen(ext)+1); /* terminator, too */
/* make the new name */
memcpy(ext+moveby-strlen(dfs_pairs[i][other_name]),dfs_pairs[i][other_name],strlen(dfs_pairs[i][other_name]));
} }
} }
else { /* dual suffix */
if ( !memcmp(ext - this_suffix_len,this_suffix,this_suffix_len) ) {
dfs_pair = j;
memmove(ext + other_suffix_len - this_suffix_len, ext,strlen(ext)+1); /* move the extension and terminator, too */
memcpy (ext - this_suffix_len, other_suffix,other_suffix_len); /* overwrite with new suffix */
}
} }
/* did we find a name for the other file? */ }
if (dfs_name==-1) goto fail; }
#if 0 /* see if the filename had a suitable L/R-pair name */
printf("input is: %s\n" if (dfs_pair == -1)
"other file would be: %s\n", goto fail;
filename,filename2);
#endif
dual_stream = streamFile->open(streamFile,filename2,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!dual_stream) goto fail;
new_stream = init_vgmstream_internal(dual_stream, /* try to init other channel (new_filename now has the opposite name) */
0 /* don't do dual file on this, to prevent recursion */ dual_streamFile = streamFile->open(streamFile,new_filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
); if (!dual_streamFile) goto fail;
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 */ /* see if we were able to open the file, and if everything matched nicely */
if (new_stream && if (!(new_vgmstream &&
new_stream->channels == 1 && new_vgmstream->channels == 1 &&
/* we have seen legitimate pairs where these are off by one... */ /* we have seen legitimate pairs where these are off by one...
/* but leaving it commented out until I can find those and recheck */ * but leaving it commented out until I can find those and recheck */
/* abs(new_stream->num_samples-opened_stream->num_samples <= 1) && */ /* abs(new_vgmstream->num_samples-opened_vgmstream->num_samples <= 1) && */
new_stream->num_samples == opened_stream->num_samples && new_vgmstream->num_samples == opened_vgmstream->num_samples &&
new_stream->sample_rate == opened_stream->sample_rate && new_vgmstream->sample_rate == opened_vgmstream->sample_rate &&
new_stream->meta_type == opened_stream->meta_type && new_vgmstream->meta_type == opened_vgmstream->meta_type &&
new_stream->coding_type == opened_stream->coding_type && new_vgmstream->coding_type == opened_vgmstream->coding_type &&
new_stream->layout_type == opened_stream->layout_type && new_vgmstream->layout_type == opened_vgmstream->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 &&
/* check even if the layout doesn't use them, because it is /* check even if the layout doesn't use them, because it is
* difficult to determine when it does, and they should be zero * difficult to determine when it does, and they should be zero otherwise, anyway */
* otherwise, anyway */ new_vgmstream->interleave_block_size == opened_vgmstream->interleave_block_size &&
new_stream->interleave_block_size == opened_stream->interleave_block_size && new_vgmstream->interleave_smallblock_size == opened_vgmstream->interleave_smallblock_size)) {
new_stream->interleave_smallblock_size == opened_stream->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. */ /* We seem to have a usable, matching file. Merge in the second channel. */
{
VGMSTREAMCHANNEL * new_chans; VGMSTREAMCHANNEL * new_chans;
VGMSTREAMCHANNEL * new_loop_chans = NULL; VGMSTREAMCHANNEL * new_loop_chans = NULL;
VGMSTREAMCHANNEL * new_start_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)); new_chans = calloc(2,sizeof(VGMSTREAMCHANNEL));
if (!new_chans) goto fail; if (!new_chans) goto fail;
memcpy(&new_chans[dfs_name],&opened_stream->ch[0],sizeof(VGMSTREAMCHANNEL)); memcpy(&new_chans[dfs_pair],&opened_vgmstream->ch[0],sizeof(VGMSTREAMCHANNEL));
memcpy(&new_chans[dfs_name^1],&new_stream->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 /* loop and start will be initialized later, we just need to allocate them here */
* allocate them here */
new_start_chans = calloc(2,sizeof(VGMSTREAMCHANNEL)); new_start_chans = calloc(2,sizeof(VGMSTREAMCHANNEL));
if (!new_start_chans) { if (!new_start_chans) {
free(new_chans); free(new_chans);
goto fail; goto fail;
} }
if (opened_stream->loop_ch) { if (opened_vgmstream->loop_ch) {
new_loop_chans = calloc(2,sizeof(VGMSTREAMCHANNEL)); new_loop_chans = calloc(2,sizeof(VGMSTREAMCHANNEL));
if (!new_loop_chans) { if (!new_loop_chans) {
free(new_chans); free(new_chans);
@ -2264,28 +2280,29 @@ static void try_dual_file_stereo(VGMSTREAM * opened_stream, STREAMFILE *streamFi
/* remove the existing structures */ /* remove the existing structures */
/* not using close_vgmstream as that would close the file */ /* not using close_vgmstream as that would close the file */
free(opened_stream->ch); free(opened_vgmstream->ch);
free(new_stream->ch); free(new_vgmstream->ch);
free(opened_stream->start_ch); free(opened_vgmstream->start_ch);
free(new_stream->start_ch); free(new_vgmstream->start_ch);
if (opened_stream->loop_ch) { if (opened_vgmstream->loop_ch) {
free(opened_stream->loop_ch); free(opened_vgmstream->loop_ch);
free(new_stream->loop_ch); free(new_vgmstream->loop_ch);
} }
/* fill in the new structures */ /* fill in the new structures */
opened_stream->ch = new_chans; opened_vgmstream->ch = new_chans;
opened_stream->start_ch = new_start_chans; opened_vgmstream->start_ch = new_start_chans;
opened_stream->loop_ch = new_loop_chans; opened_vgmstream->loop_ch = new_loop_chans;
/* stereo! */ /* stereo! */
opened_stream->channels = 2; opened_vgmstream->channels = 2;
/* discard the second VGMSTREAM */ /* discard the second VGMSTREAM */
free(new_stream); free(new_vgmstream);
} }
fail: fail:
return; return;
} }

View File

@ -212,14 +212,14 @@ typedef enum {
layout_ast_blocked, layout_ast_blocked,
layout_halpst_blocked, layout_halpst_blocked,
layout_xa_blocked, layout_xa_blocked,
layout_ea_blocked, layout_blocked_ea_schl,
layout_blocked_ea_1snh, layout_blocked_ea_1snh,
layout_caf_blocked, layout_caf_blocked,
layout_wsi_blocked, layout_wsi_blocked,
layout_str_snds_blocked, layout_str_snds_blocked,
layout_ws_aud_blocked, layout_ws_aud_blocked,
layout_matx_blocked, layout_matx_blocked,
layout_de2_blocked, layout_blocked_dec,
layout_xvas_blocked, layout_xvas_blocked,
layout_vs_blocked, layout_vs_blocked,
layout_emff_ps2_blocked, layout_emff_ps2_blocked,
@ -231,15 +231,15 @@ typedef enum {
layout_ps2_adm_blocked, layout_ps2_adm_blocked,
layout_dsp_bdsp_blocked, layout_dsp_bdsp_blocked,
layout_mxch_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_tra_blocked, /* DefJam Rapstar .tra blocks */
layout_ps2_iab_blocked, layout_ps2_iab_blocked,
layout_ps2_strlr_blocked, layout_ps2_strlr_blocked,
layout_rws_blocked, layout_rws_blocked,
layout_hwas_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_awc, /* Rockstar AWC */
layout_blocked_vgs, /* Guitar Hero II */ layout_blocked_vgs, /* Guitar Hero II (PS2) */
/* otherwise odd */ /* otherwise odd */
layout_acm, /* libacm layout */ layout_acm, /* libacm layout */
@ -281,7 +281,7 @@ typedef enum {
/* Nintendo */ /* Nintendo */
meta_STRM, /* Nintendo STRM */ meta_STRM, /* Nintendo STRM */
meta_RSTM, /* Nintendo RSTM (similar to STRM) */ meta_RSTM, /* Nintendo RSTM (Revolution Stream, similar to STRM) */
meta_AFC, /* AFC */ meta_AFC, /* AFC */
meta_AST, /* AST */ meta_AST, /* AST */
meta_RWSD, /* single-stream RWSD */ meta_RWSD, /* single-stream RWSD */
@ -306,7 +306,6 @@ typedef enum {
meta_UTF_DSP, /* CRI ADPCM_WII, like AAX with DSP */ meta_UTF_DSP, /* CRI ADPCM_WII, like AAX with DSP */
meta_NGC_ADPDTK, /* NGC DTK/ADP (.adp/dkt DTK) [no header_id] */ 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_RSF, /* Retro Studios RSF (Metroid Prime .rsf) [no header_id] */
meta_HALPST, /* HAL Labs HALPST */ meta_HALPST, /* HAL Labs HALPST */
meta_GCSW, /* GCSW (PCM) */ meta_GCSW, /* GCSW (PCM) */
@ -470,7 +469,7 @@ typedef enum {
meta_WS_AUD, /* Westwood Studios .aud */ meta_WS_AUD, /* Westwood Studios .aud */
meta_WS_AUD_old, /* Westwood Studios .aud, old style */ meta_WS_AUD_old, /* Westwood Studios .aud, old style */
meta_RIFF_WAVE, /* RIFF, for WAVs */ 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_labl, /* RIFF w/ loop Markers in LIST-adtl-labl */
meta_RIFF_WAVE_smpl, /* RIFF w/ loop data in smpl chunk */ meta_RIFF_WAVE_smpl, /* RIFF w/ loop data in smpl chunk */
meta_RIFF_WAVE_MWV, /* .mwv RIFF w/ loop data in ctrl chunk pflt */ 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_DC_KCEY, /* Konami KCE Yokohama KCEYCOMP (DC games) */
meta_ACM, /* InterPlay ACM header */ meta_ACM, /* InterPlay ACM header */
meta_MUS_ACM, /* MUS playlist of InterPlay ACM files */ 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_VS, /* Men in Black .vs */
meta_FFXI_BGW, /* FFXI (PC) BGW */ meta_FFXI_BGW, /* FFXI (PC) BGW */
meta_FFXI_SPW, /* FFXI (PC) SPW */ 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_2PFS, // Konami: Mahoromatic: Moetto - KiraKira Maid-San, GANTZ (PS2)
meta_PS2_VBK, // Disney's Stitch - Experiment 626 meta_PS2_VBK, // Disney's Stitch - Experiment 626
meta_OTM, // Otomedius (Arcade) meta_OTM, // Otomedius (Arcade)
meta_CSTM, // Nintendo 3DS CSTM meta_CSTM, // Nintendo 3DS CSTM (Century Stream)
meta_FSTM, // Nintendo Wii U FSTM meta_FSTM, // Nintendo Wii U FSTM (caFe? Stream)
meta_3DS_IDSP, // Nintendo 3DS/Wii U IDSP meta_3DS_IDSP, // Nintendo 3DS/Wii U IDSP
meta_KT_WIIBGM, // Koei Tecmo WiiBGM meta_KT_WIIBGM, // Koei Tecmo WiiBGM
meta_MCA, /* Capcom MCA "MADP" */ meta_MCA, /* Capcom MCA "MADP" */
@ -627,6 +626,7 @@ typedef enum {
meta_NSW_OPUS, /* Lego City Undercover (Switch) */ meta_NSW_OPUS, /* Lego City Undercover (Switch) */
meta_PC_AL2, /* Conquest of Elysium 3 (PC) */ meta_PC_AL2, /* Conquest of Elysium 3 (PC) */
meta_PC_AST, /* Dead Rising (PC) */ meta_PC_AST, /* Dead Rising (PC) */
meta_NAAC, /* Namco AAC (3DS) */
meta_UBI_SB, /* Ubisoft banks */ meta_UBI_SB, /* Ubisoft banks */
#ifdef VGM_USE_VORBIS #ifdef VGM_USE_VORBIS
@ -721,36 +721,32 @@ typedef struct {
int32_t loop_start_sample; /* first sample of the loop (included in the loop) */ 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) */ int32_t loop_end_sample; /* last sample of the loop (not included in the loop) */
/* channels */ /* layouts/block */
VGMSTREAMCHANNEL * ch; /* pointer to array of channels */ 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 * 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 */ 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 current_sample; /* number of samples we've passed */
int32_t samples_into_block; /* number of samples into the current block */ 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) */ 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_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 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 */ off_t next_block_offset; /* offset of header of the next block */
int block_count; /* count of "semi" block in total block */ /* layout/block loop state */
/* loop layout (saved values) */
int32_t loop_sample; /* saved from current_sample, should be loop_start_sample... */ int32_t loop_sample; /* saved from current_sample, should be loop_start_sample... */
int32_t loop_samples_into_block;/* saved from samples_into_block */ int32_t loop_samples_into_block;/* saved from samples_into_block */
off_t loop_block_offset; /* saved from current_block_offset */ off_t loop_block_offset; /* saved from current_block_offset */
size_t loop_block_size; /* saved from current_block_size */ 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 */ off_t loop_next_block_offset; /* saved from next_block_offset */
/* loop internals */ /* loop state */
int hit_loop; /* have we seen the loop yet? */ int hit_loop; /* have we seen the loop yet? */
/* counters for "loop + play end of the stream instead of fading" (not used/needed otherwise) */ /* 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) */ int loop_count; /* number of complete loops (1=looped once) */