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