mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-29 08:44:32 +01:00
Merge pull request #210 from bnnm/aica-layers-eatrax-misc
AICA, layers, EATrax, misc
This commit is contained in:
commit
3ef2f62ad1
@ -122,11 +122,12 @@ like foobar or Winamp don't react well to that, they may be renamed for
|
||||
vgmstream (mainly to get looping in some cases).
|
||||
- .ac3 to .lac3
|
||||
- .aac to .laac
|
||||
- .asf to .sng (EA formats)
|
||||
- .mp4 to .lmp4
|
||||
- .ogg to .logg
|
||||
- .opus to .lopus
|
||||
- .stm to .lstm
|
||||
- .wav to .lwav (or .xwav in rare original Xbox cases)
|
||||
- .wav to .lwav
|
||||
Command line tools don't have this restriction and will accept the original
|
||||
filename.
|
||||
|
||||
|
@ -26,8 +26,7 @@ extern char * optarg;
|
||||
extern int optind, opterr, optopt;
|
||||
|
||||
|
||||
static void make_wav_header(uint8_t * buf, int32_t sample_count, int32_t sample_rate, int channels);
|
||||
static void make_smpl_chunk(uint8_t * buf, int32_t loop_start, int32_t loop_end);
|
||||
static size_t make_wav_header(uint8_t * buf, size_t buf_size, int32_t sample_count, int32_t sample_rate, int channels, int smpl_chunk, int32_t loop_start, int32_t loop_end);
|
||||
|
||||
static void usage(const char * name) {
|
||||
fprintf(stderr,"vgmstream CLI decoder " VERSION " " __DATE__ "\n"
|
||||
@ -316,16 +315,23 @@ int main(int argc, char ** argv) {
|
||||
|
||||
|
||||
/* slap on a .wav header */
|
||||
if (only_stereo != -1) {
|
||||
make_wav_header((uint8_t*)buf, len_samples, vgmstream->sample_rate, 2);
|
||||
} else {
|
||||
make_wav_header((uint8_t*)buf, len_samples, vgmstream->sample_rate, vgmstream->channels);
|
||||
{
|
||||
uint8_t wav_buf[0x100];
|
||||
int channels = (only_stereo != -1) ? 2 : vgmstream->channels;
|
||||
int smpl_chunk = (write_lwav && vgmstream->loop_flag);
|
||||
size_t bytes_done;
|
||||
|
||||
bytes_done = make_wav_header(wav_buf,0x100,
|
||||
len_samples, vgmstream->sample_rate, channels,
|
||||
smpl_chunk, vgmstream->loop_start_sample, vgmstream->loop_end_sample);
|
||||
|
||||
/* once "smpl" with loops is written we don't want actual file looping */
|
||||
if (smpl_chunk) {
|
||||
vgmstream_force_loop(vgmstream, 0, 0,0);
|
||||
}
|
||||
|
||||
fwrite(wav_buf,sizeof(uint8_t),bytes_done,outfile);
|
||||
}
|
||||
if (write_lwav && vgmstream->loop_flag) { // Adding space for smpl chunk at end
|
||||
int32_t bytecount = get_32bitLE((uint8_t*)buf + 4);
|
||||
put_32bitLE((uint8_t*)buf + 4, bytecount + 0x44);
|
||||
}
|
||||
fwrite(buf,1,0x2c,outfile);
|
||||
|
||||
/* decode forever */
|
||||
while (play_forever) {
|
||||
@ -374,11 +380,6 @@ int main(int argc, char ** argv) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Writing "smpl" chunck at the end */
|
||||
if (write_lwav && vgmstream->loop_flag) {
|
||||
make_smpl_chunk((uint8_t*)buf, vgmstream->loop_start_sample, vgmstream->loop_end_sample);
|
||||
fwrite(buf,1,0x44,outfile);
|
||||
}
|
||||
fclose(outfile);
|
||||
outfile = NULL;
|
||||
|
||||
@ -389,9 +390,6 @@ int main(int argc, char ** argv) {
|
||||
fprintf(stderr,"failed to open %s for output\n",outfilename_reset);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
/* slap on a .wav header */
|
||||
make_wav_header((uint8_t*)buf, len_samples, vgmstream->sample_rate, vgmstream->channels);
|
||||
fwrite(buf,1,0x2c,outfile);
|
||||
|
||||
reset_vgmstream(vgmstream);
|
||||
|
||||
@ -409,6 +407,29 @@ int main(int argc, char ** argv) {
|
||||
vgmstream_force_loop(vgmstream, 0, 0,0);
|
||||
}
|
||||
|
||||
/* slap on a .wav header */
|
||||
{
|
||||
uint8_t wav_buf[0x100];
|
||||
int channels = (only_stereo != -1) ? 2 : vgmstream->channels;
|
||||
int smpl_chunk = (write_lwav && vgmstream->loop_flag);
|
||||
size_t bytes_done;
|
||||
|
||||
bytes_done = make_wav_header(wav_buf,0x100,
|
||||
len_samples, vgmstream->sample_rate, channels,
|
||||
smpl_chunk, vgmstream->loop_start_sample, vgmstream->loop_end_sample);
|
||||
|
||||
/* once "smpl" with looping is written we don't want actual file looping */
|
||||
if (smpl_chunk) {
|
||||
vgmstream_force_loop(vgmstream, 0, 0,0);
|
||||
}
|
||||
|
||||
if (write_lwav && vgmstream->loop_flag) { // Adding space for smpl chunk at end
|
||||
int32_t bytecount = get_32bitLE((uint8_t*)buf + 4);
|
||||
put_32bitLE((uint8_t*)buf + 4, bytecount + 0x44);
|
||||
}
|
||||
fwrite(wav_buf,sizeof(uint8_t),bytes_done,outfile);
|
||||
}
|
||||
|
||||
/* decode */
|
||||
for (i = 0; i < len_samples; i += BUFSIZE) {
|
||||
int toget=BUFSIZE;
|
||||
@ -452,35 +473,6 @@ int main(int argc, char ** argv) {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* make a header for PCM .wav
|
||||
* buffer must be 0x2c bytes
|
||||
*/
|
||||
static void make_wav_header(uint8_t * buf, int32_t sample_count, int32_t sample_rate, int channels) {
|
||||
size_t bytecount;
|
||||
|
||||
bytecount = sample_count*channels*sizeof(sample);
|
||||
|
||||
memcpy(buf+0, "RIFF", 4); /* RIFF header */
|
||||
put_32bitLE(buf+4, (int32_t)(bytecount+0x2c-8)); /* size of RIFF */
|
||||
|
||||
memcpy(buf+8, "WAVE", 4); /* WAVE header */
|
||||
|
||||
memcpy(buf+0xc, "fmt ", 4); /* WAVE fmt chunk */
|
||||
put_32bitLE(buf+0x10, 0x10); /* size of WAVE fmt chunk */
|
||||
put_16bitLE(buf+0x14, 1); /* compression code 1=PCM */
|
||||
put_16bitLE(buf+0x16, channels); /* channel count */
|
||||
put_32bitLE(buf+0x18, sample_rate); /* sample rate */
|
||||
put_32bitLE(buf+0x1c, sample_rate*channels*sizeof(sample)); /* bytes per second */
|
||||
put_16bitLE(buf+0x20, (int16_t)(channels*sizeof(sample))); /* block align */
|
||||
put_16bitLE(buf+0x22, sizeof(sample)*8); /* significant bits per sample */
|
||||
|
||||
/* PCM has no extra format bytes, so we don't even need to specify a count */
|
||||
|
||||
memcpy(buf+0x24, "data", 4); /* WAVE data chunk */
|
||||
put_32bitLE(buf+0x28, (int32_t)bytecount); /* size of WAVE data chunk */
|
||||
}
|
||||
|
||||
static void make_smpl_chunk(uint8_t * buf, int32_t loop_start, int32_t loop_end) {
|
||||
int i;
|
||||
|
||||
@ -500,3 +492,44 @@ static void make_smpl_chunk(uint8_t * buf, int32_t loop_start, int32_t loop_end)
|
||||
put_32bitLE(buf+60, 0);
|
||||
put_32bitLE(buf+64, 0);
|
||||
}
|
||||
|
||||
/* make a RIFF header for .wav */
|
||||
static size_t make_wav_header(uint8_t * buf, size_t buf_size, int32_t sample_count, int32_t sample_rate, int channels, int smpl_chunk, int32_t loop_start, int32_t loop_end) {
|
||||
size_t data_size, header_size;
|
||||
|
||||
data_size = sample_count*channels*sizeof(sample);
|
||||
header_size = 0x2c;
|
||||
if (smpl_chunk)
|
||||
header_size += 0x3c+ 0x08;
|
||||
|
||||
if (header_size > buf_size)
|
||||
goto fail;
|
||||
|
||||
memcpy(buf+0x00, "RIFF", 4); /* RIFF header */
|
||||
put_32bitLE(buf+4, (int32_t)(header_size - 0x08 + data_size)); /* size of RIFF */
|
||||
|
||||
memcpy(buf+0x08, "WAVE", 4); /* WAVE header */
|
||||
|
||||
memcpy(buf+0x0c, "fmt ", 4); /* WAVE fmt chunk */
|
||||
put_32bitLE(buf+0x10, 0x10); /* size of WAVE fmt chunk */
|
||||
put_16bitLE(buf+0x14, 1); /* compression code 1=PCM */
|
||||
put_16bitLE(buf+0x16, channels); /* channel count */
|
||||
put_32bitLE(buf+0x18, sample_rate); /* sample rate */
|
||||
put_32bitLE(buf+0x1c, sample_rate*channels*sizeof(sample)); /* bytes per second */
|
||||
put_16bitLE(buf+0x20, (int16_t)(channels*sizeof(sample))); /* block align */
|
||||
put_16bitLE(buf+0x22, sizeof(sample)*8); /* significant bits per sample */
|
||||
|
||||
if (smpl_chunk) {
|
||||
make_smpl_chunk(buf+0x24, loop_start, loop_end);
|
||||
memcpy(buf+0x24+0x3c+0x08, "data", 0x04); /* WAVE data chunk */
|
||||
put_32bitLE(buf+0x28+0x3c+0x08, (int32_t)data_size); /* size of WAVE data chunk */
|
||||
}
|
||||
else {
|
||||
memcpy(buf+0x24, "data", 0x04); /* WAVE data chunk */
|
||||
put_32bitLE(buf+0x28, (int32_t)data_size); /* size of WAVE data chunk */
|
||||
}
|
||||
|
||||
return header_size;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
@ -59,7 +59,6 @@ void decode_ngc_afc(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci
|
||||
|
||||
/* pcm_decoder */
|
||||
void decode_pcm16LE(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_pcm16LE_XOR_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_pcm16BE(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_pcm16_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian);
|
||||
void decode_pcm8(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
@ -76,7 +75,6 @@ size_t pcm_bytes_to_samples(size_t bytes, int channels, int bits_per_sample);
|
||||
/* psx_decoder */
|
||||
void decode_psx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_psx_badflags(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_psx_bmdx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_psx_configurable(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int frame_size);
|
||||
void decode_hevag(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
size_t ps_bytes_to_samples(size_t bytes, int channels);
|
||||
@ -118,9 +116,10 @@ void decode_msadpcm_mono(VGMSTREAM * vgmstream, sample * outbuf, int32_t first_s
|
||||
long msadpcm_bytes_to_samples(long bytes, int block_size, int channels);
|
||||
|
||||
/* yamaha_decoder */
|
||||
void decode_aica(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_aica(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo);
|
||||
void decode_yamaha(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
void decode_yamaha_nxap(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
size_t aica_bytes_to_samples(size_t bytes, int channels);
|
||||
size_t yamaha_bytes_to_samples(size_t bytes, int channels);
|
||||
|
||||
/* nds_procyon_decoder */
|
||||
|
@ -297,15 +297,9 @@ fail:
|
||||
int ffmpeg_make_riff_xma2_from_xma2_chunk(uint8_t * buf, size_t buf_size, off_t xma2_offset, size_t xma2_size, size_t data_size, STREAMFILE *streamFile) {
|
||||
uint8_t chunk[0x100];
|
||||
size_t riff_size;
|
||||
size_t xma2_final_size = xma2_size;
|
||||
int xma2_chunk_version = read_8bit(xma2_offset,streamFile);
|
||||
|
||||
/* FFmpeg can't parse v3 "XMA2" chunks so we'll have to extend (8 bytes in the middle) */
|
||||
if (xma2_chunk_version == 3)
|
||||
xma2_final_size += 0x8;
|
||||
riff_size = 4+4+ 4 + 4+4+xma2_final_size + 4+4;
|
||||
|
||||
if (buf_size < riff_size || xma2_final_size > 0x100)
|
||||
riff_size = 4+4+ 4 + 4+4+xma2_size + 4+4;
|
||||
if (buf_size < riff_size || xma2_size > 0x100)
|
||||
goto fail;
|
||||
if (read_streamfile(chunk,xma2_offset,xma2_size, streamFile) != xma2_size)
|
||||
goto fail;
|
||||
@ -316,20 +310,11 @@ int ffmpeg_make_riff_xma2_from_xma2_chunk(uint8_t * buf, size_t buf_size, off_t
|
||||
memcpy(buf+0x08, "WAVE", 4);
|
||||
|
||||
memcpy(buf+0x0c, "XMA2", 4);
|
||||
put_32bitLE(buf+0x10, xma2_final_size);
|
||||
if (xma2_chunk_version == 3) {
|
||||
/* old XMA2 v3: change to v4 (extra 8 bytes in the middle); always BE */
|
||||
put_8bit (buf+0x14 + 0x00, 4); /* v4 */
|
||||
memcpy (buf+0x14 + 0x01, chunk+1, 0xF); /* first v3 part (fixed) */
|
||||
put_32bitBE(buf+0x14 + 0x10, 0x000010D6); /* extra v4 BE: "EncodeOptions" (not used by FFmpeg) */
|
||||
put_32bitBE(buf+0x14 + 0x14, 0); /* extra v4 BE: "PsuedoBytesPerSec" (not used by FFmpeg) */
|
||||
memcpy (buf+0x14 + 0x18, chunk+0x10, xma2_size - 0x10); /* second v3 part (variable size) */
|
||||
} else {
|
||||
memcpy(buf+0x14, chunk, xma2_size);
|
||||
}
|
||||
put_32bitLE(buf+0x10, xma2_size);
|
||||
memcpy(buf+0x14, chunk, xma2_size);
|
||||
|
||||
memcpy(buf+0x14+xma2_final_size, "data", 4);
|
||||
put_32bitLE(buf+0x14+xma2_final_size+4, data_size); /* data size */
|
||||
memcpy(buf+0x14+xma2_size, "data", 4);
|
||||
put_32bitLE(buf+0x14+xma2_size+4, data_size); /* data size */
|
||||
|
||||
return riff_size;
|
||||
|
||||
|
@ -364,6 +364,10 @@ ffmpeg_codec_data * init_ffmpeg_config(STREAMFILE *streamFile, uint8_t * header,
|
||||
memcpy(&data->config, config, sizeof(ffmpeg_custom_config));
|
||||
}
|
||||
|
||||
/* ignore bad combos */
|
||||
if ((header && !header_size) || (!header && header_size))
|
||||
goto fail;
|
||||
|
||||
/* fake header to trick FFmpeg into demuxing/decoding the stream */
|
||||
if (header_size > 0) {
|
||||
data->header_size = header_size;
|
||||
|
@ -78,15 +78,6 @@ void decode_pcm16_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspa
|
||||
}
|
||||
}
|
||||
|
||||
void decode_pcm16LE_XOR_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i;
|
||||
int32_t sample_count;
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
outbuf[sample_count]=read_16bitLE(stream->offset+i*2*channelspacing,stream->streamfile)^stream->key_xor;
|
||||
}
|
||||
}
|
||||
|
||||
static int expand_ulaw(uint8_t ulawbyte) {
|
||||
int sign, segment, quantization, new_sample;
|
||||
const int bias = 0x84;
|
||||
|
@ -110,52 +110,6 @@ void decode_psx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
|
||||
stream->adpcm_history2_32=hist2;
|
||||
}
|
||||
|
||||
/* encrypted */
|
||||
void decode_psx_bmdx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
|
||||
int predict_nr, shift_factor, sample;
|
||||
int32_t hist1=stream->adpcm_history1_32;
|
||||
int32_t hist2=stream->adpcm_history2_32;
|
||||
|
||||
short scale;
|
||||
int i;
|
||||
int32_t sample_count;
|
||||
uint8_t flag;
|
||||
|
||||
int framesin = first_sample/28;
|
||||
int head = read_8bit(stream->offset+framesin*16,stream->streamfile) ^ stream->bmdx_xor;
|
||||
|
||||
predict_nr = ((head >> 4) & 0xf);
|
||||
shift_factor = (head & 0xf);
|
||||
flag = read_8bit(stream->offset+framesin*16+1,stream->streamfile);
|
||||
|
||||
first_sample = first_sample % 28;
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
|
||||
sample=0;
|
||||
|
||||
if(flag<0x07) {
|
||||
|
||||
short sample_byte = (short)read_8bit(stream->offset+(framesin*16)+2+i/2,stream->streamfile);
|
||||
if (i/2 == 0)
|
||||
sample_byte = (short)(int8_t)(sample_byte+stream->bmdx_add);
|
||||
|
||||
scale = ((i&1 ?
|
||||
sample_byte >> 4 :
|
||||
sample_byte & 0x0f)<<12);
|
||||
|
||||
sample=(int)((scale >> shift_factor)+hist1*VAG_f[predict_nr][0]+hist2*VAG_f[predict_nr][1]);
|
||||
}
|
||||
|
||||
outbuf[sample_count] = clamp16(sample);
|
||||
hist2=hist1;
|
||||
hist1=sample;
|
||||
}
|
||||
stream->adpcm_history1_32=hist1;
|
||||
stream->adpcm_history2_32=hist2;
|
||||
}
|
||||
|
||||
/* some games have garbage (?) in their flags, this decoder just ignores that byte */
|
||||
void decode_psx_badflags(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
|
||||
|
@ -15,8 +15,8 @@ static const int scale_delta[16] = {
|
||||
};
|
||||
|
||||
|
||||
/* Yamaha AICA ADPCM, as seen in Dreamcast. Possibly like RIFF codec 0x20 or used in older arcade sound chips. */
|
||||
void decode_aica(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
/* raw Yamaha ADPCM a.k.a AICA as it's mainly used in Naomi/Dreamcast (also in RIFF and older arcade sound chips). */
|
||||
void decode_aica(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo) {
|
||||
int i, sample_count;
|
||||
|
||||
int32_t hist1 = stream->adpcm_history1_16;
|
||||
@ -28,8 +28,12 @@ void decode_aica(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
int sample_nibble, sample_decoded, sample_delta;
|
||||
off_t byte_offset = (stream->offset) + i/2;
|
||||
int nibble_shift = (i&1?4:0); /* low nibble first */
|
||||
off_t byte_offset = is_stereo ?
|
||||
stream->offset + i : /* stereo: one nibble per channel */
|
||||
stream->offset + i/2; /* mono: consecutive nibbles */
|
||||
int nibble_shift = is_stereo ?
|
||||
(!(channel&1) ? 0:4) : /* even = low/L, odd = high/R */
|
||||
(!(i&1) ? 0:4); /* low nibble first */
|
||||
|
||||
/* Yamaha/AICA expand, but same result as IMA's (((delta * 2 + 1) * step) >> 3) */
|
||||
sample_nibble = ((read_8bit(byte_offset,stream->streamfile) >> nibble_shift))&0xf;
|
||||
@ -141,6 +145,11 @@ void decode_yamaha_nxap(VGMSTREAMCHANNEL * stream, sample * outbuf, int channels
|
||||
stream->adpcm_step_index = step_size;
|
||||
}
|
||||
|
||||
size_t aica_bytes_to_samples(size_t bytes, int channels) {
|
||||
/* 2 samples per byte (2 nibbles) in stereo or mono config */
|
||||
return bytes * 2 / channels;
|
||||
}
|
||||
|
||||
size_t yamaha_bytes_to_samples(size_t bytes, int channels) {
|
||||
int block_align = 0x40;
|
||||
|
||||
|
@ -183,6 +183,7 @@ static const char* extension_list[] = {
|
||||
"matx",
|
||||
"mc3",
|
||||
"mca",
|
||||
"mcadpcm",
|
||||
"mcg",
|
||||
"mds",
|
||||
"mdsp",
|
||||
@ -201,6 +202,7 @@ static const char* extension_list[] = {
|
||||
"msd",
|
||||
"msf",
|
||||
"mss",
|
||||
"msv", //txh/reserved [Fight Club (PS2)]
|
||||
"msvp",
|
||||
"mta2",
|
||||
"mtaf",
|
||||
@ -349,6 +351,7 @@ static const char* extension_list[] = {
|
||||
"vgs",
|
||||
"vgv",
|
||||
"vig",
|
||||
"vis", //txth/reserved [AirForce Delta (PS2)]
|
||||
"vms",
|
||||
"voi",
|
||||
"vpk",
|
||||
@ -376,6 +379,7 @@ static const char* extension_list[] = {
|
||||
"wsd",
|
||||
"wsi",
|
||||
"wv2", //txth/reserved [Slave Zero (PC)]
|
||||
"wve",
|
||||
"wvs",
|
||||
|
||||
"xa",
|
||||
@ -437,7 +441,6 @@ typedef struct {
|
||||
|
||||
static const coding_info coding_info_list[] = {
|
||||
{coding_PCM16LE, "Little Endian 16-bit PCM"},
|
||||
{coding_PCM16LE_XOR_int, "Little Endian 16-bit PCM with 2 byte interleave and XOR obfuscation"},
|
||||
{coding_PCM16BE, "Big Endian 16-bit PCM"},
|
||||
{coding_PCM16_int, "16-bit PCM with 2 byte interleave (block)"},
|
||||
{coding_PCM8, "8-bit PCM"},
|
||||
@ -466,7 +469,6 @@ static const coding_info coding_info_list[] = {
|
||||
{coding_XA, "CD-ROM XA 4-bit ADPCM"},
|
||||
{coding_PSX, "Playstation 4-bit ADPCM"},
|
||||
{coding_PSX_badflags, "Playstation 4-bit ADPCM (bad flags)"},
|
||||
{coding_PSX_bmdx, "Playstation 4-bit ADPCM (BMDX encryption)"},
|
||||
{coding_PSX_cfg, "Playstation 4-bit ADPCM (configurable)"},
|
||||
{coding_HEVAG, "Playstation Vita HEVAG 4-bit ADPCM"},
|
||||
|
||||
@ -501,6 +503,7 @@ static const coding_info coding_info_list[] = {
|
||||
{coding_MSADPCM, "Microsoft 4-bit ADPCM"},
|
||||
{coding_WS, "Westwood Studios VBR ADPCM"},
|
||||
{coding_AICA, "Yamaha AICA 4-bit ADPCM"},
|
||||
{coding_AICA_int, "Yamaha AICA 4-bit ADPCM (mono/interleave)"},
|
||||
{coding_YAMAHA, "Yamaha 4-bit ADPCM"},
|
||||
{coding_YAMAHA_NXAP, "Yamaha NXAP 4-bit ADPCM"},
|
||||
{coding_NDS_PROCYON, "Procyon Studio Digital Sound Elements NDS 4-bit APDCM"},
|
||||
@ -557,42 +560,45 @@ static const layout_info layout_info_list[] = {
|
||||
{layout_interleave, "interleave"},
|
||||
|
||||
{layout_segmented, "segmented"},
|
||||
{layout_aix, "AIX interleave, internally 18-byte interleaved"},
|
||||
{layout_scd_int, "SCD multistream interleave"},
|
||||
{layout_layered, "layered"},
|
||||
{layout_aix, "AIX"},
|
||||
|
||||
{layout_mxch_blocked, "MxCh blocked"},
|
||||
{layout_ast_blocked, "AST blocked"},
|
||||
{layout_halpst_blocked, "HALPST blocked"},
|
||||
{layout_xa_blocked, "CD-ROM XA"},
|
||||
{layout_blocked_mxch, "blocked (MxCh)"},
|
||||
{layout_blocked_ast, "blocked (AST)"},
|
||||
{layout_blocked_halpst, "blocked (HALPST)"},
|
||||
{layout_blocked_xa, "blocked (XA)"},
|
||||
{layout_blocked_ea_schl, "blocked (EA SCHl)"},
|
||||
{layout_blocked_ea_1snh, "blocked (EA 1SNh)"},
|
||||
{layout_blocked_caf, "blocked (CAF)"},
|
||||
{layout_blocked_wsi, "blocked (WSI)"},
|
||||
{layout_xvas_blocked, ".xvas blocked"},
|
||||
{layout_str_snds_blocked, ".str SNDS blocked"},
|
||||
{layout_ws_aud_blocked, "Westwood Studios .aud blocked"},
|
||||
{layout_matx_blocked, "Matrix .matx blocked"},
|
||||
{layout_blocked_xvas, "blocked (.xvas)"},
|
||||
{layout_blocked_str_snds, "blocked (.str SNDS)"},
|
||||
{layout_blocked_ws_aud, "blocked (Westwood Studios .aud)"},
|
||||
{layout_blocked_matx, "blocked (Matrix .matx)"},
|
||||
{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"},
|
||||
{layout_gsb_blocked, "GSB blocked"},
|
||||
{layout_thp_blocked, "THP Movie Audio blocked"},
|
||||
{layout_filp_blocked, "FILp blocked"},
|
||||
{layout_blocked_vs, "blocked (vs)"},
|
||||
{layout_blocked_emff_ps2, "blocked (EMFF PS2)"},
|
||||
{layout_blocked_emff_ngc, "blocked (EMFF NGC)"},
|
||||
{layout_blocked_gsb, "blocked (GSB)"},
|
||||
{layout_blocked_thp, "blocked (THP Movie Audio)"},
|
||||
{layout_blocked_filp, "blocked (FILP)"},
|
||||
{layout_blocked_ea_swvr, "blocked (EA SWVR)"},
|
||||
{layout_blocked_adm, "blocked (ADM)"},
|
||||
{layout_dsp_bdsp_blocked, "DSP blocked"},
|
||||
{layout_blocked_bdsp, "blocked (BDSP)"},
|
||||
{layout_blocked_ivaud, "blocked (IVAUD)"},
|
||||
{layout_ps2_iab_blocked, "IAB blocked"},
|
||||
{layout_ps2_strlr_blocked, "The Bouncer STR blocked"},
|
||||
{layout_blocked_ps2_iab, "blocked (IAB)"},
|
||||
{layout_blocked_ps2_strlr, "blocked (The Bouncer STR)"},
|
||||
{layout_blocked_rws, "blocked (RWS)"},
|
||||
{layout_blocked_hwas, "blocked (HWAS)"},
|
||||
{layout_tra_blocked, "TRA blocked"},
|
||||
{layout_blocked_tra, "blocked (TRA)"},
|
||||
{layout_blocked_ea_sns, "blocked (EA SNS)"},
|
||||
{layout_blocked_awc, "blocked (AWC)"},
|
||||
{layout_blocked_vgs, "blocked (VGS)"},
|
||||
{layout_blocked_vawx, "blocked (VAWX)"},
|
||||
{layout_blocked_xvag_subsong, "blocked (XVAG subsong)"},
|
||||
{layout_blocked_ea_wve_au00, "blocked (EA WVE au00)"},
|
||||
{layout_blocked_ea_wve_ad10, "blocked (EA WVE Ad10)"},
|
||||
{layout_blocked_sthd, "blocked (STHD)"},
|
||||
};
|
||||
|
||||
static const meta_info meta_info_list[] = {
|
||||
@ -753,7 +759,7 @@ static const meta_info meta_info_list[] = {
|
||||
{meta_RSD6AT3P, "Radical RSD6/AT3+ header"},
|
||||
{meta_RSD6WMA, "Radical RSD6/WMA header"},
|
||||
{meta_DC_ASD, "ASD Header"},
|
||||
{meta_NAOMI_SPSD, "SPSD Header"},
|
||||
{meta_NAOMI_SPSD, "Naomi SPSD header"},
|
||||
{meta_FFXI_BGW, "BGW BGMStream header"},
|
||||
{meta_FFXI_SPW, "SPW SeWave header"},
|
||||
{meta_PS2_ASS, "ASS Header"},
|
||||
@ -840,7 +846,7 @@ static const meta_info meta_info_list[] = {
|
||||
{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_PDT, "Hudson .PDT header"},
|
||||
{meta_NGC_RKV, "Legacy of Kain - Blood Omen 2 RKV GC header"},
|
||||
{meta_DSP_DDSP, ".DDSP header"},
|
||||
{meta_P3D, "Radical P3D header"},
|
||||
@ -913,7 +919,7 @@ static const meta_info meta_info_list[] = {
|
||||
{meta_XB3D_ADX, "Xenoblade 3D ADX header"},
|
||||
{meta_HCA, "CRI MiddleWare HCA Header"},
|
||||
{meta_PS2_SVAG_SNK, "SNK SVAG header"},
|
||||
{meta_PS2_VDS_VDM, "Graffiti Kingdom VDS/VDM header"},
|
||||
{meta_PS2_VDS_VDM, "Procyon Studio VDS/VDM header"},
|
||||
{meta_X360_CXS, "tri-Crescendo CXS header"},
|
||||
{meta_AKB, "Square-Enix AKB header"},
|
||||
{meta_NUB_XMA, "Namco NUB XMA header"},
|
||||
@ -972,10 +978,13 @@ static const meta_info meta_info_list[] = {
|
||||
{meta_WAVE_segmented, "EngineBlack .WAVE header (segmented)"},
|
||||
{meta_SMV, "Cho Aniki Zero .SMV header"},
|
||||
{meta_NXAP, "Nex NXAP header"},
|
||||
{meta_EA_WVE_AU00, "Electronic Arts WVE (au00) header"},
|
||||
{meta_EA_WVE_AD10, "Electronic Arts WVE (Ad10) header"},
|
||||
{meta_STHD, "Dream Factory STHD header"},
|
||||
{meta_MP4, "MP4/AAC header"},
|
||||
{meta_PCM_SRE, "Capcom .PCM+SRE header"},
|
||||
{meta_DSP_MCADPCM, "Bethesda .mcadpcm header"},
|
||||
|
||||
#ifdef VGM_USE_MP4V2
|
||||
{meta_MP4, "AAC header"},
|
||||
#endif
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
{meta_FFmpeg, "FFmpeg supported file format"},
|
||||
#endif
|
||||
|
@ -65,20 +65,20 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM *
|
||||
if (vgmstream->samples_into_block==samples_this_block
|
||||
/*&& vgmstream->current_sample < vgmstream->num_samples*/) { /* don't go past last block */
|
||||
switch (vgmstream->layout_type) {
|
||||
case layout_ast_blocked:
|
||||
ast_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
case layout_blocked_ast:
|
||||
block_update_ast(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_mxch_blocked:
|
||||
mxch_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
case layout_blocked_mxch:
|
||||
block_update_mxch(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_halpst_blocked:
|
||||
case layout_blocked_halpst:
|
||||
if (vgmstream->next_block_offset>=0)
|
||||
halpst_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
block_update_halpst(vgmstream->next_block_offset,vgmstream);
|
||||
else
|
||||
vgmstream->current_block_offset = -1;
|
||||
break;
|
||||
case layout_xa_blocked:
|
||||
xa_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
case layout_blocked_xa:
|
||||
block_update_xa(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_ea_schl:
|
||||
block_update_ea_schl(vgmstream->next_block_offset,vgmstream);
|
||||
@ -92,38 +92,38 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM *
|
||||
case layout_blocked_wsi:
|
||||
block_update_wsi(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_str_snds_blocked:
|
||||
str_snds_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
case layout_blocked_str_snds:
|
||||
block_update_str_snds(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_ws_aud_blocked:
|
||||
ws_aud_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
case layout_blocked_ws_aud:
|
||||
block_update_ws_aud(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_matx_blocked:
|
||||
matx_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
case layout_blocked_matx:
|
||||
block_update_matx(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
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);
|
||||
case layout_blocked_emff_ps2:
|
||||
block_update_emff_ps2(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_emff_ngc_blocked:
|
||||
emff_ngc_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
case layout_blocked_emff_ngc:
|
||||
block_update_emff_ngc(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_gsb_blocked:
|
||||
gsb_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
case layout_blocked_gsb:
|
||||
block_update_gsb(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_vs_blocked:
|
||||
vs_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
case layout_blocked_vs:
|
||||
block_update_vs(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_xvas_blocked:
|
||||
xvas_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
case layout_blocked_xvas:
|
||||
block_update_xvas(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_thp_blocked:
|
||||
thp_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
case layout_blocked_thp:
|
||||
block_update_thp(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_filp_blocked:
|
||||
filp_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
case layout_blocked_filp:
|
||||
block_update_filp(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_ivaud:
|
||||
block_update_ivaud(vgmstream->next_block_offset,vgmstream);
|
||||
@ -134,17 +134,17 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM *
|
||||
case layout_blocked_adm:
|
||||
block_update_adm(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_dsp_bdsp_blocked:
|
||||
dsp_bdsp_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
case layout_blocked_bdsp:
|
||||
block_update_bdsp(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_tra_blocked:
|
||||
tra_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
case layout_blocked_tra:
|
||||
block_update_tra(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_ps2_iab_blocked:
|
||||
ps2_iab_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
case layout_blocked_ps2_iab:
|
||||
block_update_ps2_iab(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_ps2_strlr_blocked:
|
||||
ps2_strlr_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
case layout_blocked_ps2_strlr:
|
||||
block_update_ps2_strlr(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_rws:
|
||||
block_update_rws(vgmstream->next_block_offset,vgmstream);
|
||||
@ -167,6 +167,15 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM *
|
||||
case layout_blocked_xvag_subsong:
|
||||
block_update_xvag_subsong(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_ea_wve_au00:
|
||||
block_update_ea_wve_au00(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_ea_wve_ad10:
|
||||
block_update_ea_wve_ad10(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_sthd:
|
||||
block_update_sthd(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* set up for the block at the given offset */
|
||||
void ast_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
void block_update_ast(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i;
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->current_block_size = read_32bitBE(
|
@ -2,7 +2,7 @@
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* set up for the block at the given offset */
|
||||
void dsp_bdsp_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
void block_update_bdsp(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i;
|
||||
|
||||
vgmstream->current_block_offset = block_offset;
|
@ -21,7 +21,7 @@ void block_update_ea_schl(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
|
||||
block_samples = 0;
|
||||
|
||||
if (id == 0x5343446C || id == 0x5344454E) { /* "SCDl" "SDEN" audio data */
|
||||
if (id == 0x5343446C || id == 0x5344454E || id == 0x53444652) { /* "SCDl" "SDEN" "SDFR" audio data */
|
||||
switch(vgmstream->coding_type) {
|
||||
case coding_PSX:
|
||||
block_samples = ps_bytes_to_samples(block_size-0x10, vgmstream->channels);
|
||||
@ -37,7 +37,7 @@ void block_update_ea_schl(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
block_size = 0x04;
|
||||
}
|
||||
|
||||
if (id == 0x5343486C || id == 0x5348454E) { /* "SCHl" "SHEN" end block */
|
||||
if (id == 0x5343486C || id == 0x5348454E || id == 0x53484652) { /* "SCHl" "SHEN" "SHFR" end block */
|
||||
new_schl = 1;
|
||||
}
|
||||
}
|
||||
@ -53,8 +53,8 @@ void block_update_ea_schl(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
break;
|
||||
block_offset += block_size;
|
||||
|
||||
/* "SCEl" are aligned to 0x80 usually, but causes problems if not 32b-aligned (ex. Need for Speed 2 PC) */
|
||||
if ((id == 0x5343456C || id == 0x5345454E) && block_offset % 0x04) {
|
||||
/* "SCEl" "SEEN" "SEFR" are aligned to 0x80 usually, but causes problems if not 32b-aligned (ex. Need for Speed 2 PC) */
|
||||
if ((id == 0x5343456C || id == 0x5345454E || id == 0x53454652) && block_offset % 0x04) {
|
||||
block_offset += 0x04 - (block_offset % 0x04);
|
||||
}
|
||||
}
|
||||
|
42
src/layout/blocked_ea_wve_ad10.c
Normal file
42
src/layout/blocked_ea_wve_ad10.c
Normal file
@ -0,0 +1,42 @@
|
||||
#include "layout.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
|
||||
/* EA style blocks, one block per channel when stereo */
|
||||
void block_update_ea_wve_ad10(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
STREAMFILE* streamFile = vgmstream->ch[0].streamfile;
|
||||
int i;
|
||||
size_t block_size = 0;
|
||||
size_t file_size = get_streamfile_size(streamFile);
|
||||
|
||||
|
||||
while (block_offset < file_size) {
|
||||
uint32_t block_id = read_32bitBE(block_offset+0x00, streamFile);
|
||||
|
||||
block_size = read_32bitBE(block_offset+0x04, streamFile);
|
||||
|
||||
if (block_id == 0x41643130 || block_id == 0x41643131) { /* "Ad10/Ad11" audio block/footer found */
|
||||
break;
|
||||
}
|
||||
/* rest may be "MDEC" video blocks */
|
||||
|
||||
block_offset += block_size;
|
||||
}
|
||||
|
||||
/* EOF reads (unsure if this helps) */
|
||||
if (block_offset >= file_size) {
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->next_block_offset = block_offset + 0x04;
|
||||
vgmstream->current_block_size = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* set offsets */
|
||||
for (i = 0; i < vgmstream->channels; i++) {
|
||||
vgmstream->ch[i].offset = block_offset + block_size*i + 0x08;
|
||||
}
|
||||
|
||||
vgmstream->current_block_size = block_size - 0x08; /* one block per channel */
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->next_block_offset = block_offset + block_size*vgmstream->channels;
|
||||
}
|
37
src/layout/blocked_ea_wve_au00.c
Normal file
37
src/layout/blocked_ea_wve_au00.c
Normal file
@ -0,0 +1,37 @@
|
||||
#include "layout.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
|
||||
/* EA style blocks */
|
||||
void block_update_ea_wve_au00(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
STREAMFILE* streamFile = vgmstream->ch[0].streamfile;
|
||||
int i;
|
||||
size_t block_size = 0, interleave;
|
||||
size_t file_size = get_streamfile_size(streamFile);
|
||||
|
||||
|
||||
while (block_offset < file_size) {
|
||||
uint32_t block_id = read_32bitBE(block_offset+0x00, streamFile);
|
||||
|
||||
block_size = read_32bitBE(block_offset+0x04, streamFile);
|
||||
|
||||
if (block_id == 0x61753030 || block_id == 0x61753031) { /* "au00/au01" audio block/footer found */
|
||||
break;
|
||||
}
|
||||
/* rest may be "MDEC" video blocks */
|
||||
|
||||
block_offset += block_size;
|
||||
}
|
||||
|
||||
/* size adjusted to frame boundaries as blocks have padding */
|
||||
interleave = ((block_size - 0x10) / vgmstream->interleave_block_size * vgmstream->interleave_block_size) / vgmstream->channels;
|
||||
|
||||
/* set offsets */
|
||||
for (i = 0; i < vgmstream->channels; i++) {
|
||||
vgmstream->ch[i].offset = (block_offset + 0x10) + interleave*i;
|
||||
}
|
||||
|
||||
vgmstream->current_block_size = interleave;
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->next_block_offset = block_offset + block_size;
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* set up for the block at the given offset */
|
||||
void emff_ps2_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
void block_update_emff_ps2(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i;
|
||||
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
@ -17,7 +17,7 @@ void emff_ps2_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
}
|
||||
}
|
||||
|
||||
void emff_ngc_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
void block_update_emff_ngc(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i;
|
||||
|
||||
vgmstream->current_block_offset = block_offset;
|
@ -2,7 +2,7 @@
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* set up for the block at the given offset */
|
||||
void filp_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
void block_update_filp(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i;
|
||||
|
||||
vgmstream->current_block_offset = block_offset;
|
@ -2,7 +2,7 @@
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* set up for the block at the given offset */
|
||||
void gsb_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
void block_update_gsb(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i;
|
||||
int block_header_size = 0x20; /*from header*/
|
||||
int block_channel_size = 0x8000; /*from header, per channel*/
|
@ -2,7 +2,7 @@
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* set up for the block at the given offset */
|
||||
void halpst_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
void block_update_halpst(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i, header_length;
|
||||
/* header length must be a multiple of 0x20 */
|
||||
header_length = (4+8*vgmstream->channels+0x1f)/0x20*0x20;
|
@ -2,7 +2,7 @@
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* set up for the block at the given offset */
|
||||
void matx_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
void block_update_matx(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i;
|
||||
|
||||
vgmstream->current_block_offset = block_offset;
|
@ -2,7 +2,7 @@
|
||||
#include "../vgmstream.h"
|
||||
|
||||
//MxCh blocked layout as used by Lego Island
|
||||
void mxch_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
void block_update_mxch(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->next_block_offset = block_offset +
|
||||
read_32bitLE(vgmstream->current_block_offset+4,vgmstream->ch[0].streamfile)+8;
|
@ -2,7 +2,7 @@
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* set up for the block at the given offset */
|
||||
void ps2_iab_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
void block_update_ps2_iab(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i;
|
||||
|
||||
vgmstream->current_block_offset = block_offset;
|
@ -2,7 +2,7 @@
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* set up for the block at the given offset */
|
||||
void ps2_strlr_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
void block_update_ps2_strlr(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i;
|
||||
|
||||
vgmstream->current_block_offset = block_offset;
|
22
src/layout/blocked_sthd.c
Normal file
22
src/layout/blocked_sthd.c
Normal file
@ -0,0 +1,22 @@
|
||||
#include "layout.h"
|
||||
|
||||
/* Dream Factory STHD blocks */
|
||||
void block_update_sthd(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
STREAMFILE* streamFile = vgmstream->ch[0].streamfile;
|
||||
size_t block_size, channel_size;
|
||||
off_t data_offset;
|
||||
int i;
|
||||
|
||||
block_size = 0x800;
|
||||
data_offset = read_16bitLE(block_offset + 0x04, streamFile);
|
||||
channel_size = read_16bitLE(block_offset + 0x16, streamFile);
|
||||
/* 0x06: num channels, 0x10: total blocks, 0x12: block count, 0x14(2): null, 0x18: block count + 1 */
|
||||
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->current_block_size = channel_size;
|
||||
vgmstream->next_block_offset = block_offset + block_size;
|
||||
|
||||
for (i = 0; i < vgmstream->channels; i++) {
|
||||
vgmstream->ch[i].offset = block_offset + data_offset + channel_size*i;
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* set up for the block at the given offset */
|
||||
void str_snds_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
void block_update_str_snds(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
off_t current_chunk;
|
||||
size_t file_size;
|
||||
int i;
|
@ -2,7 +2,7 @@
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* set up for the block at the given offset */
|
||||
void thp_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
void block_update_thp(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i,j;
|
||||
STREAMFILE *streamFile=vgmstream->ch[0].streamfile;
|
||||
off_t start_offset;
|
@ -2,7 +2,7 @@
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* set up for the block at the given offset (first 32bytes is useless for decoding) */
|
||||
void tra_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
void block_update_tra(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i;
|
||||
|
||||
vgmstream->current_block_offset = block_offset;
|
@ -2,7 +2,7 @@
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* set up for the block at the given offset */
|
||||
void vs_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
void block_update_vs(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i;
|
||||
|
||||
for (i=0;i<vgmstream->channels;i++) {
|
@ -2,7 +2,7 @@
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* set up for the block at the given offset */
|
||||
void ws_aud_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
void block_update_ws_aud(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i;
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->current_block_size = read_16bitLE(
|
@ -3,7 +3,7 @@
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* set up for the block at the given offset */
|
||||
void xa_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
void block_update_xa(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i;
|
||||
int8_t currentChannel=0;
|
||||
int8_t subAudio=0;
|
@ -2,7 +2,7 @@
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* set up for the block at the given offset */
|
||||
void xvas_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
void block_update_xvas(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i;
|
||||
|
||||
vgmstream->current_block_offset = block_offset;
|
122
src/layout/layered.c
Normal file
122
src/layout/layered.c
Normal file
@ -0,0 +1,122 @@
|
||||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* TODO: currently only properly handles mono substreams */
|
||||
/* TODO: there must be a reasonable way to respect the loop settings, as
|
||||
the substreams are in their own little world.
|
||||
Currently the VGMSTREAMs layers loop internally and the external/base VGMSTREAM
|
||||
doesn't actually loop, and would ignore any altered values/loop_flag. */
|
||||
|
||||
#define INTERLEAVE_BUF_SIZE 512
|
||||
|
||||
|
||||
void render_vgmstream_layered(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
|
||||
sample interleave_buf[INTERLEAVE_BUF_SIZE];
|
||||
int32_t samples_done = 0;
|
||||
layered_layout_data *data = vgmstream->layout_data;
|
||||
|
||||
while (samples_done < sample_count) {
|
||||
int32_t samples_to_do = INTERLEAVE_BUF_SIZE;
|
||||
int c;
|
||||
if (samples_to_do > sample_count - samples_done)
|
||||
samples_to_do = sample_count - samples_done;
|
||||
|
||||
for (c=0; c < data->layer_count; c++) {
|
||||
int32_t i;
|
||||
|
||||
render_vgmstream(interleave_buf, samples_to_do, data->layers[c]);
|
||||
|
||||
for (i=0; i < samples_to_do; i++) {
|
||||
buffer[(samples_done+i)*data->layer_count + c] = interleave_buf[i];
|
||||
}
|
||||
}
|
||||
|
||||
samples_done += samples_to_do;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
layered_layout_data* init_layout_layered(int layer_count) {
|
||||
layered_layout_data *data = NULL;
|
||||
|
||||
if (layer_count <= 0 || layer_count > 255)
|
||||
goto fail;
|
||||
|
||||
data = calloc(1, sizeof(layered_layout_data));
|
||||
if (!data) goto fail;
|
||||
|
||||
data->layer_count = layer_count;
|
||||
|
||||
data->layers = calloc(layer_count, sizeof(VGMSTREAM*));
|
||||
if (!data->layers) goto fail;
|
||||
|
||||
return data;
|
||||
fail:
|
||||
free_layout_layered(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int setup_layout_layered(layered_layout_data* data) {
|
||||
int i;
|
||||
|
||||
/* setup each VGMSTREAM (roughly equivalent to vgmstream.c's init_vgmstream_internal stuff) */
|
||||
for (i = 0; i < data->layer_count; i++) {
|
||||
if (!data->layers[i])
|
||||
goto fail;
|
||||
|
||||
if (data->layers[i]->num_samples <= 0)
|
||||
goto fail;
|
||||
|
||||
//todo only mono at the moment
|
||||
if (data->layers[i]->channels != 1)
|
||||
goto fail;
|
||||
|
||||
if (i > 0) {
|
||||
/* a bit weird, but no matter */
|
||||
if (data->layers[i]->sample_rate != data->layers[i-1]->sample_rate) {
|
||||
VGM_LOG("layered layout: layer %i has different sample rate\n", i);
|
||||
}
|
||||
|
||||
/* also weird */
|
||||
if (data->layers[i]->coding_type != data->layers[i-1]->coding_type) {
|
||||
VGM_LOG("layered layout: layer %i has different coding type\n", i);
|
||||
}
|
||||
}
|
||||
|
||||
//todo could check if layers'd loop match vs main, etc
|
||||
|
||||
/* save start things so we can restart for seeking/looping */
|
||||
memcpy(data->layers[i]->start_ch,data->layers[i]->ch,sizeof(VGMSTREAMCHANNEL)*data->layers[i]->channels);
|
||||
memcpy(data->layers[i]->start_vgmstream,data->layers[i],sizeof(VGMSTREAM));
|
||||
}
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
return 0; /* caller is expected to free */
|
||||
}
|
||||
|
||||
void free_layout_layered(layered_layout_data *data) {
|
||||
int i;
|
||||
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
if (data->layers) {
|
||||
for (i = 0; i < data->layer_count; i++) {
|
||||
close_vgmstream(data->layers[i]);
|
||||
}
|
||||
free(data->layers);
|
||||
}
|
||||
free(data);
|
||||
}
|
||||
|
||||
void reset_layout_layered(layered_layout_data *data) {
|
||||
int i;
|
||||
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
for (i = 0; i < data->layer_count; i++) {
|
||||
reset_vgmstream(data->layers[i]);
|
||||
}
|
||||
}
|
@ -7,53 +7,32 @@
|
||||
/* blocked layouts */
|
||||
void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
|
||||
|
||||
void ast_block_update(off_t block_ofset, VGMSTREAM * vgmstream);
|
||||
|
||||
void mxch_block_update(off_t block_ofset, VGMSTREAM * vgmstream);
|
||||
|
||||
void halpst_block_update(off_t block_ofset, VGMSTREAM * vgmstream);
|
||||
|
||||
void xa_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void block_update_ast(off_t block_ofset, VGMSTREAM * vgmstream);
|
||||
void block_update_mxch(off_t block_ofset, VGMSTREAM * vgmstream);
|
||||
void block_update_halpst(off_t block_ofset, VGMSTREAM * vgmstream);
|
||||
void block_update_xa(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
void block_update_ea_schl(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
void block_update_ea_1snh(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
void block_update_caf(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
void block_update_wsi(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void str_snds_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void ws_aud_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void matx_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void block_update_str_snds(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
void block_update_ws_aud(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
void block_update_matx(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
void block_update_dec(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void vs_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void emff_ps2_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void emff_ngc_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void gsb_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void xvas_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void thp_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void filp_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void block_update_vs(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
void block_update_emff_ps2(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
void block_update_emff_ngc(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
void block_update_gsb(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
void block_update_xvas(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
void block_update_thp(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
void block_update_filp(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
void block_update_ivaud(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
void block_update_ea_swvr(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
void block_update_adm(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void dsp_bdsp_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void tra_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void ps2_iab_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void ps2_strlr_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void block_update_bdsp(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
void block_update_tra(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
void block_update_ps2_iab(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
void block_update_ps2_strlr(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
void block_update_rws(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
void block_update_hwas(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
void block_update_ea_sns(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
@ -61,6 +40,9 @@ void block_update_awc(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
void block_update_vgs(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
void block_update_vawx(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
void block_update_xvag_subsong(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
void block_update_ea_wve_au00(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
void block_update_ea_wve_ad10(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
void block_update_sthd(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
/* other layouts */
|
||||
void render_vgmstream_interleave(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
|
||||
@ -75,6 +57,10 @@ int setup_layout_segmented(segmented_layout_data* data);
|
||||
void free_layout_segmented(segmented_layout_data *data);
|
||||
void reset_layout_segmented(segmented_layout_data *data);
|
||||
|
||||
void render_vgmstream_scd_int(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
|
||||
void render_vgmstream_layered(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
|
||||
layered_layout_data* init_layout_layered(int layer_count);
|
||||
int setup_layout_layered(layered_layout_data* data);
|
||||
void free_layout_layered(layered_layout_data *data);
|
||||
void reset_layout_layered(layered_layout_data *data);
|
||||
|
||||
#endif
|
||||
|
@ -1,38 +0,0 @@
|
||||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* TODO: currently only properly handles mono substreams */
|
||||
/* TODO: there must be a reasonable way to respect the loop settings, as is
|
||||
the substreams are in their own little world */
|
||||
|
||||
#define INTERLEAVE_BUF_SIZE 512
|
||||
void render_vgmstream_scd_int(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
|
||||
sample interleave_buf[INTERLEAVE_BUF_SIZE];
|
||||
int32_t samples_done = 0;
|
||||
scd_int_codec_data *data = vgmstream->codec_data;
|
||||
|
||||
while (samples_done < sample_count)
|
||||
{
|
||||
int32_t samples_to_do = INTERLEAVE_BUF_SIZE;
|
||||
int c;
|
||||
if (samples_to_do > sample_count - samples_done)
|
||||
samples_to_do = sample_count - samples_done;
|
||||
|
||||
for (c=0; c < data->substream_count; c++)
|
||||
{
|
||||
int32_t i;
|
||||
|
||||
render_vgmstream(interleave_buf,
|
||||
samples_to_do, data->substreams[c]);
|
||||
|
||||
for (i=0; i < samples_to_do; i++)
|
||||
{
|
||||
buffer[(samples_done+i)*data->substream_count + c] = interleave_buf[i];
|
||||
}
|
||||
}
|
||||
|
||||
samples_done += samples_to_do;
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,70 +1,5 @@
|
||||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
segmented_layout_data* init_layout_segmented(int segment_count) {
|
||||
segmented_layout_data *data = NULL;
|
||||
|
||||
if (segment_count <= 0 || segment_count > 255)
|
||||
goto fail;
|
||||
|
||||
data = calloc(1, sizeof(segmented_layout_data));
|
||||
if (!data) goto fail;
|
||||
|
||||
data->segment_count = segment_count;
|
||||
data->current_segment = 0;
|
||||
|
||||
data->segments = calloc(segment_count, sizeof(VGMSTREAM*));
|
||||
if (!data->segments) goto fail;
|
||||
|
||||
return data;
|
||||
fail:
|
||||
free_layout_segmented(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int setup_layout_segmented(segmented_layout_data* data) {
|
||||
int i;
|
||||
|
||||
/* setup each VGMSTREAM (roughly equivalent to vgmstream.c's init_vgmstream_internal stuff) */
|
||||
for (i = 0; i < data->segment_count; i++) {
|
||||
if (!data->segments[i])
|
||||
goto fail;
|
||||
|
||||
if (data->segments[i]->num_samples <= 0)
|
||||
goto fail;
|
||||
|
||||
/* shouldn't happen */
|
||||
if (data->segments[i]->loop_flag != 0) {
|
||||
VGM_LOG("segmented layout: segment %i is looped\n", i);
|
||||
data->segments[i]->loop_flag = 0;
|
||||
}
|
||||
|
||||
if (i > 0) {
|
||||
if (data->segments[i]->channels != data->segments[i-1]->channels)
|
||||
goto fail;
|
||||
|
||||
/* a bit weird, but no matter */
|
||||
if (data->segments[i]->sample_rate != data->segments[i-1]->sample_rate) {
|
||||
VGM_LOG("segmented layout: segment %i has different sample rate\n", i);
|
||||
}
|
||||
|
||||
//if (data->segments[i]->coding_type != data->segments[i-1]->coding_type)
|
||||
// goto fail; /* perfectly acceptable */
|
||||
}
|
||||
|
||||
|
||||
/* save start things so we can restart for seeking/looping */
|
||||
memcpy(data->segments[i]->start_ch,data->segments[i]->ch,sizeof(VGMSTREAMCHANNEL)*data->segments[i]->channels);
|
||||
memcpy(data->segments[i]->start_vgmstream,data->segments[i],sizeof(VGMSTREAM));
|
||||
}
|
||||
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
return 0; /* caller is expected to free */
|
||||
}
|
||||
|
||||
|
||||
void render_vgmstream_segmented(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
|
||||
@ -110,6 +45,69 @@ void render_vgmstream_segmented(sample * buffer, int32_t sample_count, VGMSTREAM
|
||||
}
|
||||
|
||||
|
||||
segmented_layout_data* init_layout_segmented(int segment_count) {
|
||||
segmented_layout_data *data = NULL;
|
||||
|
||||
if (segment_count <= 0 || segment_count > 255)
|
||||
goto fail;
|
||||
|
||||
data = calloc(1, sizeof(segmented_layout_data));
|
||||
if (!data) goto fail;
|
||||
|
||||
data->segment_count = segment_count;
|
||||
data->current_segment = 0;
|
||||
|
||||
data->segments = calloc(segment_count, sizeof(VGMSTREAM*));
|
||||
if (!data->segments) goto fail;
|
||||
|
||||
return data;
|
||||
fail:
|
||||
free_layout_segmented(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int setup_layout_segmented(segmented_layout_data* data) {
|
||||
int i;
|
||||
|
||||
/* setup each VGMSTREAM (roughly equivalent to vgmstream.c's init_vgmstream_internal stuff) */
|
||||
for (i = 0; i < data->segment_count; i++) {
|
||||
if (!data->segments[i])
|
||||
goto fail;
|
||||
|
||||
if (data->segments[i]->num_samples <= 0)
|
||||
goto fail;
|
||||
|
||||
/* shouldn't happen */
|
||||
if (data->segments[i]->loop_flag != 0) {
|
||||
VGM_LOG("segmented layout: segment %i is looped\n", i);
|
||||
data->segments[i]->loop_flag = 0;
|
||||
}
|
||||
|
||||
if (i > 0) {
|
||||
if (data->segments[i]->channels != data->segments[i-1]->channels)
|
||||
goto fail;
|
||||
|
||||
/* a bit weird, but no matter */
|
||||
if (data->segments[i]->sample_rate != data->segments[i-1]->sample_rate) {
|
||||
VGM_LOG("segmented layout: segment %i has different sample rate\n", i);
|
||||
}
|
||||
|
||||
//if (data->segments[i]->coding_type != data->segments[i-1]->coding_type)
|
||||
// goto fail; /* perfectly acceptable */
|
||||
}
|
||||
|
||||
|
||||
/* save start things so we can restart for seeking/looping */
|
||||
memcpy(data->segments[i]->start_ch,data->segments[i]->ch,sizeof(VGMSTREAMCHANNEL)*data->segments[i]->channels);
|
||||
memcpy(data->segments[i]->start_vgmstream,data->segments[i],sizeof(VGMSTREAM));
|
||||
}
|
||||
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
return 0; /* caller is expected to free */
|
||||
}
|
||||
|
||||
void free_layout_segmented(segmented_layout_data *data) {
|
||||
int i;
|
||||
|
||||
@ -118,8 +116,6 @@ void free_layout_segmented(segmented_layout_data *data) {
|
||||
|
||||
if (data->segments) {
|
||||
for (i = 0; i < data->segment_count; i++) {
|
||||
/* note that the close_streamfile won't do anything but deallocate itself,
|
||||
* there is only one open file in vgmstream->ch[0].streamfile */
|
||||
close_vgmstream(data->segments[i]);
|
||||
}
|
||||
free(data->segments);
|
||||
|
@ -216,10 +216,18 @@
|
||||
RelativePath=".\meta\aix_streamfile.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\awc_xma_streamfile.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\bar_streamfile.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\ea_eaac_eatrax_streamfile.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\sqex_scd_streamfile.h"
|
||||
>
|
||||
@ -387,6 +395,14 @@
|
||||
<File
|
||||
RelativePath=".\meta\ea_eaac.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\ea_wve_au00.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\ea_wve_ad10.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\emff.c"
|
||||
@ -757,6 +773,10 @@
|
||||
<File
|
||||
RelativePath=".\meta\pc_xa30.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\pcm_sre.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\scd_pcm.c"
|
||||
@ -1210,6 +1230,10 @@
|
||||
RelativePath=".\meta\sqex_sead.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\sthd.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\stm.c"
|
||||
>
|
||||
@ -1691,11 +1715,11 @@
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\layout\ast_blocked.c"
|
||||
RelativePath=".\layout\blocked_ast.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\layout\bdsp_blocked.c"
|
||||
RelativePath=".\layout\blocked_bdsp.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
@ -1710,6 +1734,14 @@
|
||||
RelativePath=".\layout\blocked_ea_1snh.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\layout\blocked_ea_wve_au00.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\layout\blocked_ea_wve_ad10.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\layout\blocked_vawx.c"
|
||||
>
|
||||
@ -1739,23 +1771,23 @@
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\layout\emff_blocked.c"
|
||||
RelativePath=".\layout\blocked_emff.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\layout\filp_blocked.c"
|
||||
RelativePath=".\layout\blocked_filp.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\layout\gsb_blocked.c"
|
||||
RelativePath=".\layout\blocked_gsb.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\layout\halpst_blocked.c"
|
||||
RelativePath=".\layout\blocked_halpst.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\layout\ims_block.c"
|
||||
RelativePath=".\layout\blocked_matx.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
@ -1767,7 +1799,7 @@
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\layout\mxch_blocked.c"
|
||||
RelativePath=".\layout\blocked_mxch.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
@ -1779,11 +1811,11 @@
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\layout\ps2_iab_blocked.c"
|
||||
RelativePath=".\layout\blocked_ps2_iab.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\layout\ps2_strlr_blocked.c"
|
||||
RelativePath=".\layout\blocked_ps2_strlr.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
@ -1794,32 +1826,36 @@
|
||||
RelativePath=".\layout\blocked_rws.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\layout\blocked_sthd.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\layout\blocked_hwas.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\layout\scd_int_layout.c"
|
||||
RelativePath=".\layout\layered.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\layout\str_snds_blocked.c"
|
||||
RelativePath=".\layout\blocked_str_snds.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\layout\thp_blocked.c"
|
||||
RelativePath=".\layout\blocked_thp.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\layout\tra_blocked.c"
|
||||
RelativePath=".\layout\blocked_tra.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\layout\vs_blocked.c"
|
||||
RelativePath=".\layout\blocked_vs.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\layout\ws_aud_blocked.c"
|
||||
RelativePath=".\layout\blocked_ws_aud.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
@ -1827,11 +1863,11 @@
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\layout\xa_blocked.c"
|
||||
RelativePath=".\layout\blocked_xa.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\layout\xvas_block.c"
|
||||
RelativePath=".\layout\blocked_xvas.c"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
|
@ -96,7 +96,9 @@
|
||||
<ClInclude Include="meta\adx_keys.h" />
|
||||
<ClInclude Include="meta\aax_utf.h" />
|
||||
<ClInclude Include="meta\aix_streamfile.h" />
|
||||
<ClInclude Include="meta\awc_xma_streamfile.h" />
|
||||
<ClInclude Include="meta\bar_streamfile.h" />
|
||||
<ClInclude Include="meta\ea_eaac_eatrax_streamfile.h" />
|
||||
<ClInclude Include="meta\sqex_scd_streamfile.h" />
|
||||
<ClInclude Include="meta\meta.h" />
|
||||
<ClInclude Include="meta\hca_keys.h" />
|
||||
@ -121,10 +123,10 @@
|
||||
<ClCompile Include="coding\mp4_aac_decoder.c" />
|
||||
<ClCompile Include="coding\mtaf_decoder.c" />
|
||||
<ClCompile Include="coding\mta2_decoder.c" />
|
||||
<ClCompile Include="layout\ps2_iab_blocked.c" />
|
||||
<ClCompile Include="layout\ps2_strlr_blocked.c" />
|
||||
<ClCompile Include="layout\scd_int_layout.c" />
|
||||
<ClCompile Include="layout\tra_blocked.c" />
|
||||
<ClCompile Include="layout\blocked_ps2_iab.c" />
|
||||
<ClCompile Include="layout\blocked_ps2_strlr.c" />
|
||||
<ClCompile Include="layout\layered.c" />
|
||||
<ClCompile Include="layout\blocked_tra.c" />
|
||||
<ClCompile Include="meta\akb.c" />
|
||||
<ClCompile Include="meta\awc.c" />
|
||||
<ClCompile Include="meta\bcstm.c" />
|
||||
@ -165,6 +167,7 @@
|
||||
<ClCompile Include="meta\seg.c" />
|
||||
<ClCompile Include="meta\sqex_scd.c" />
|
||||
<ClCompile Include="meta\sqex_sead.c" />
|
||||
<ClCompile Include="meta\sthd.c" />
|
||||
<ClCompile Include="meta\tun.c" />
|
||||
<ClCompile Include="meta\txth.c" />
|
||||
<ClCompile Include="meta\wii_ras.c" />
|
||||
@ -212,6 +215,8 @@
|
||||
<ClCompile Include="meta\ea_schl_fixed.c" />
|
||||
<ClCompile Include="meta\ea_1snh.c" />
|
||||
<ClCompile Include="meta\ea_eaac.c" />
|
||||
<ClCompile Include="meta\ea_wve_au00.c" />
|
||||
<ClCompile Include="meta\ea_wve_ad10.c" />
|
||||
<ClCompile Include="meta\emff.c" />
|
||||
<ClCompile Include="meta\exakt_sc.c" />
|
||||
<ClCompile Include="meta\ffw.c" />
|
||||
@ -288,6 +293,7 @@
|
||||
<ClCompile Include="meta\pc_smp.c" />
|
||||
<ClCompile Include="meta\sab.c" />
|
||||
<ClCompile Include="meta\pc_xa30.c" />
|
||||
<ClCompile Include="meta\pcm_sre.c" />
|
||||
<ClCompile Include="meta\scd_pcm.c" />
|
||||
<ClCompile Include="meta\pona.c" />
|
||||
<ClCompile Include="meta\pos.c" />
|
||||
@ -471,8 +477,8 @@
|
||||
<ClCompile Include="coding\xa_decoder.c" />
|
||||
<ClCompile Include="layout\segmented.c" />
|
||||
<ClCompile Include="layout\aix_layout.c" />
|
||||
<ClCompile Include="layout\ast_blocked.c" />
|
||||
<ClCompile Include="layout\bdsp_blocked.c" />
|
||||
<ClCompile Include="layout\blocked_ast.c" />
|
||||
<ClCompile Include="layout\blocked_bdsp.c" />
|
||||
<ClCompile Include="layout\blocked.c" />
|
||||
<ClCompile Include="layout\blocked_awc.c" />
|
||||
<ClCompile Include="layout\blocked_ea_1snh.c" />
|
||||
@ -483,26 +489,29 @@
|
||||
<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" />
|
||||
<ClCompile Include="layout\halpst_blocked.c" />
|
||||
<ClCompile Include="layout\ims_block.c" />
|
||||
<ClCompile Include="layout\blocked_ea_wve_au00.c" />
|
||||
<ClCompile Include="layout\blocked_ea_wve_ad10.c" />
|
||||
<ClCompile Include="layout\blocked_emff.c" />
|
||||
<ClCompile Include="layout\blocked_filp.c" />
|
||||
<ClCompile Include="layout\blocked_gsb.c" />
|
||||
<ClCompile Include="layout\blocked_halpst.c" />
|
||||
<ClCompile Include="layout\blocked_matx.c" />
|
||||
<ClCompile Include="layout\interleave.c" />
|
||||
<ClCompile Include="layout\blocked_ivaud.c" />
|
||||
<ClCompile Include="layout\mxch_blocked.c" />
|
||||
<ClCompile Include="layout\blocked_mxch.c" />
|
||||
<ClCompile Include="layout\nolayout.c" />
|
||||
<ClCompile Include="layout\blocked_adm.c" />
|
||||
<ClCompile Include="layout\blocked_ea_swvr.c" />
|
||||
<ClCompile Include="layout\blocked_rws.c" />
|
||||
<ClCompile Include="layout\blocked_sthd.c" />
|
||||
<ClCompile Include="layout\blocked_hwas.c" />
|
||||
<ClCompile Include="layout\str_snds_blocked.c" />
|
||||
<ClCompile Include="layout\thp_blocked.c" />
|
||||
<ClCompile Include="layout\vs_blocked.c" />
|
||||
<ClCompile Include="layout\ws_aud_blocked.c" />
|
||||
<ClCompile Include="layout\blocked_str_snds.c" />
|
||||
<ClCompile Include="layout\blocked_thp.c" />
|
||||
<ClCompile Include="layout\blocked_vs.c" />
|
||||
<ClCompile Include="layout\blocked_ws_aud.c" />
|
||||
<ClCompile Include="layout\blocked_wsi.c" />
|
||||
<ClCompile Include="layout\xa_blocked.c" />
|
||||
<ClCompile Include="layout\xvas_block.c" />
|
||||
<ClCompile Include="layout\blocked_xa.c" />
|
||||
<ClCompile Include="layout\blocked_xvas.c" />
|
||||
<ClCompile Include="..\ext_libs\clHCA.c" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
|
@ -68,9 +68,15 @@
|
||||
<ClInclude Include="meta\aix_streamfile.h">
|
||||
<Filter>meta\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="meta\awc_xma_streamfile.h">
|
||||
<Filter>meta\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="meta\bar_streamfile.h">
|
||||
<Filter>meta\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="meta\ea_eaac_eatrax_streamfile.h">
|
||||
<Filter>meta\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="meta\sqex_scd_streamfile.h">
|
||||
<Filter>meta\Header Files</Filter>
|
||||
</ClInclude>
|
||||
@ -235,6 +241,12 @@
|
||||
<ClCompile Include="meta\ea_eaac.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\ea_wve_au00.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\ea_wve_ad10.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\emff.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
@ -448,6 +460,9 @@
|
||||
<ClCompile Include="meta\pc_xa30.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\pcm_sre.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\scd_pcm.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
@ -988,10 +1003,10 @@
|
||||
<ClCompile Include="layout\aix_layout.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="layout\ast_blocked.c">
|
||||
<ClCompile Include="layout\blocked_ast.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="layout\bdsp_blocked.c">
|
||||
<ClCompile Include="layout\blocked_bdsp.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="layout\blocked.c">
|
||||
@ -1003,6 +1018,12 @@
|
||||
<ClCompile Include="layout\blocked_ea_1snh.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="layout\blocked_ea_wve_au00.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="layout\blocked_ea_wve_ad10.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="layout\blocked_vgs.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
@ -1024,22 +1045,22 @@
|
||||
<ClCompile Include="layout\blocked_ea_sns.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="layout\emff_blocked.c">
|
||||
<ClCompile Include="layout\blocked_emff.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="layout\filp_blocked.c">
|
||||
<ClCompile Include="layout\blocked_filp.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="layout\gsb_blocked.c">
|
||||
<ClCompile Include="layout\blocked_gsb.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="layout\halpst_blocked.c">
|
||||
<ClCompile Include="layout\blocked_halpst.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="layout\blocked_hwas.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="layout\ims_block.c">
|
||||
<ClCompile Include="layout\blocked_matx.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="layout\interleave.c">
|
||||
@ -1048,7 +1069,7 @@
|
||||
<ClCompile Include="layout\blocked_ivaud.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="layout\mxch_blocked.c">
|
||||
<ClCompile Include="layout\blocked_mxch.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="layout\nolayout.c">
|
||||
@ -1063,25 +1084,28 @@
|
||||
<ClCompile Include="layout\blocked_rws.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="layout\str_snds_blocked.c">
|
||||
<ClCompile Include="layout\blocked_sthd.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="layout\thp_blocked.c">
|
||||
<ClCompile Include="layout\blocked_str_snds.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="layout\vs_blocked.c">
|
||||
<ClCompile Include="layout\blocked_thp.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="layout\ws_aud_blocked.c">
|
||||
<ClCompile Include="layout\blocked_vs.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="layout\blocked_ws_aud.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="layout\blocked_wsi.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="layout\xa_blocked.c">
|
||||
<ClCompile Include="layout\blocked_xa.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="layout\xvas_block.c">
|
||||
<ClCompile Include="layout\blocked_xvas.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\nub_vag.c">
|
||||
@ -1117,13 +1141,13 @@
|
||||
<ClCompile Include="meta\ps2_iab.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="layout\ps2_strlr_blocked.c">
|
||||
<ClCompile Include="layout\blocked_ps2_strlr.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="layout\ps2_iab_blocked.c">
|
||||
<ClCompile Include="layout\blocked_ps2_iab.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="layout\tra_blocked.c">
|
||||
<ClCompile Include="layout\blocked_tra.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="coding\lsf_decoder.c">
|
||||
@ -1144,6 +1168,9 @@
|
||||
<ClCompile Include="meta\sqex_sead.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\sthd.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\seg.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
@ -1192,7 +1219,7 @@
|
||||
<ClCompile Include="meta\ps2_hsf.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="layout\scd_int_layout.c">
|
||||
<ClCompile Include="layout\layered.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\ps2_2pfs.c">
|
||||
|
@ -28,8 +28,10 @@ VGMSTREAM * init_vgmstream_adx(STREAMFILE *streamFile) {
|
||||
uint16_t xor_start=0,xor_mult=0,xor_add=0;
|
||||
|
||||
|
||||
/* check extension, case insensitive */
|
||||
if (!check_extensions(streamFile,"adx")) goto fail;
|
||||
/* checks*/
|
||||
/* .adx: standard, .adp: Headhunter (DC) */
|
||||
if (!check_extensions(streamFile,"adx,adp"))
|
||||
goto fail;
|
||||
|
||||
/* check first 2 bytes */
|
||||
if ((uint16_t)read_16bitBE(0x00,streamFile)!=0x8000) goto fail;
|
||||
|
@ -59,7 +59,7 @@ VGMSTREAM * init_vgmstream_ast(STREAMFILE *streamFile) {
|
||||
vgmstream->loop_end_sample = read_32bitBE(0x1c,streamFile);
|
||||
|
||||
vgmstream->coding_type = coding_type;
|
||||
vgmstream->layout_type = layout_ast_blocked;
|
||||
vgmstream->layout_type = layout_blocked_ast;
|
||||
vgmstream->meta_type = meta_AST;
|
||||
|
||||
/* open the file for reading by each channel */
|
||||
@ -80,7 +80,7 @@ VGMSTREAM * init_vgmstream_ast(STREAMFILE *streamFile) {
|
||||
}
|
||||
|
||||
/* start me up */
|
||||
ast_block_update(0x40,vgmstream);
|
||||
block_update_ast(0x40,vgmstream);
|
||||
|
||||
return vgmstream;
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
#include "../coding/coding.h"
|
||||
|
||||
static STREAMFILE* setup_atsl_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size, const char* fake_ext);
|
||||
typedef enum { ATRAC3, ATRAC9, KOVS } atsl_codec;
|
||||
typedef enum { ATRAC3, ATRAC9, KOVS, KTSS } atsl_codec;
|
||||
|
||||
/* .ATSL - Koei Tecmo audio container [One Piece Pirate Warriors (PS3), Warriors All-Stars (PC)] */
|
||||
VGMSTREAM * init_vgmstream_atsl(STREAMFILE *streamFile) {
|
||||
@ -39,6 +39,7 @@ VGMSTREAM * init_vgmstream_atsl(STREAMFILE *streamFile) {
|
||||
* - 00060301 00040301 atsl in G1L from One Piece Pirate Warriors 3 (Vita)[ATRAC9]
|
||||
* - 00060301 00010301 atsl in G1L from One Piece Pirate Warriors 3 (PC)[KOVS]
|
||||
* - 000A0301 00010501 atsl in G1L from Warriors All-Stars (PC)[KOVS]
|
||||
* - 000B0301 00080601 atsl in G1l from Sengoku Musou Sanada Maru (Switch)[KTSS]
|
||||
*/
|
||||
type = read_8bit(0x0d, streamFile);
|
||||
switch(type) {
|
||||
@ -56,7 +57,12 @@ VGMSTREAM * init_vgmstream_atsl(STREAMFILE *streamFile) {
|
||||
codec = ATRAC9;
|
||||
fake_ext = "at9";
|
||||
break;
|
||||
case 0x08:
|
||||
codec = KTSS;
|
||||
fake_ext = "ktss";
|
||||
break;
|
||||
default:
|
||||
VGM_LOG("ATSL: unknown type %x\n", type);
|
||||
goto fail;
|
||||
}
|
||||
read_32bit = big_endian ? read_32bitBE : read_32bitLE;
|
||||
@ -118,6 +124,10 @@ VGMSTREAM * init_vgmstream_atsl(STREAMFILE *streamFile) {
|
||||
vgmstream = init_vgmstream_ogg_vorbis(temp_streamFile);
|
||||
if (!vgmstream) goto fail;
|
||||
break;
|
||||
case KTSS:
|
||||
vgmstream = init_vgmstream_ktss(temp_streamFile);
|
||||
if (!vgmstream) goto fail;
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ static STREAMFILE* setup_atx_streamfile(STREAMFILE *streamFile) {
|
||||
size_t subfile_size;
|
||||
|
||||
filename[filename_len - 5] = ('0'+i+1); /* ghetto digit conversion */
|
||||
new_streamFile = open_stream_name(streamFile, filename);
|
||||
new_streamFile = open_streamfile_by_filename(streamFile, filename);
|
||||
if (!new_streamFile) goto fail;
|
||||
segment_streamFiles[i] = new_streamFile;
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "awc_xma_streamfile.h"
|
||||
|
||||
typedef struct {
|
||||
int big_endian;
|
||||
@ -64,6 +65,76 @@ VGMSTREAM * init_vgmstream_awc(STREAMFILE *streamFile) {
|
||||
vgmstream->codec_endian = awc.big_endian;
|
||||
break;
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
case 0x05: { /* XMA2 (X360) */
|
||||
uint8_t buf[0x100];
|
||||
size_t bytes, block_size, block_count, substream_size;
|
||||
off_t substream_offset;
|
||||
|
||||
if (awc.is_music) {
|
||||
/* 1ch XMAs in blocks, we'll use layered layout + custom IO to get multi-FFmpegs working */
|
||||
int i;
|
||||
layered_layout_data * data = NULL;
|
||||
|
||||
/* init layout */
|
||||
data = init_layout_layered(awc.channel_count);
|
||||
if (!data) goto fail;
|
||||
vgmstream->layout_data = data;
|
||||
vgmstream->layout_type = layout_layered;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
|
||||
/* open each layer subfile */
|
||||
for (i = 0; i < awc.channel_count; i++) {
|
||||
STREAMFILE* temp_streamFile;
|
||||
int layer_channels = 1;
|
||||
|
||||
/* build the layer VGMSTREAM */
|
||||
data->layers[i] = allocate_vgmstream(layer_channels, 0);
|
||||
if (!data->layers[i]) goto fail;
|
||||
|
||||
data->layers[i]->sample_rate = awc.sample_rate;
|
||||
data->layers[i]->meta_type = meta_AWC;
|
||||
data->layers[i]->coding_type = coding_FFmpeg;
|
||||
data->layers[i]->layout_type = layout_none;
|
||||
data->layers[i]->num_samples = awc.num_samples;
|
||||
|
||||
/* setup custom IO streamfile, pass to FFmpeg and hope it's fooled */
|
||||
temp_streamFile = setup_awc_xma_streamfile(streamFile, awc.stream_offset, awc.stream_size, awc.block_chunk, awc.channel_count, i);
|
||||
if (!temp_streamFile) goto fail;
|
||||
|
||||
substream_offset = 0; /* where FFmpeg thinks data starts, which our custom streamFile will clamp */
|
||||
substream_size = get_streamfile_size(temp_streamFile); /* data of one XMA substream without blocks */
|
||||
block_size = 0x8000; /* no idea */
|
||||
block_count = substream_size / block_size; /* not accurate but not needed */
|
||||
|
||||
bytes = ffmpeg_make_riff_xma2(buf, 0x100, awc.num_samples, substream_size, layer_channels, awc.sample_rate, block_count, block_size);
|
||||
data->layers[i]->codec_data = init_ffmpeg_header_offset(temp_streamFile, buf,bytes, substream_offset,substream_size);
|
||||
|
||||
close_streamfile(temp_streamFile);
|
||||
if (!data->layers[i]->codec_data) goto fail;
|
||||
}
|
||||
|
||||
/* setup layered VGMSTREAMs */
|
||||
if (!setup_layout_layered(data))
|
||||
goto fail;
|
||||
}
|
||||
else {
|
||||
/* regular XMA for sfx */
|
||||
block_size = 0x8000; /* no idea */
|
||||
block_count = awc.stream_size / block_size; /* not accurate but not needed */
|
||||
|
||||
bytes = ffmpeg_make_riff_xma2(buf, 0x100, awc.num_samples, awc.stream_size, awc.channel_count, awc.sample_rate, block_count, block_size);
|
||||
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, awc.stream_offset,awc.stream_size);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
#ifdef VGM_USE_MPEG
|
||||
case 0x07: { /* MPEG (PS3) */
|
||||
mpeg_custom_config cfg;
|
||||
@ -80,7 +151,6 @@ VGMSTREAM * init_vgmstream_awc(STREAMFILE *streamFile) {
|
||||
}
|
||||
#endif
|
||||
|
||||
case 0x05: /* XMA2 (X360) */
|
||||
default:
|
||||
VGM_LOG("AWC: unknown codec 0x%02x\n", awc.codec);
|
||||
goto fail;
|
||||
|
257
src/meta/awc_xma_streamfile.h
Normal file
257
src/meta/awc_xma_streamfile.h
Normal file
@ -0,0 +1,257 @@
|
||||
#ifndef _AWC_XMA_STREAMFILE_H_
|
||||
#define _AWC_XMA_STREAMFILE_H_
|
||||
#include "../streamfile.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
/* config */
|
||||
off_t stream_offset;
|
||||
size_t stream_size;
|
||||
int channel_count;
|
||||
int channel;
|
||||
size_t chunk_size;
|
||||
|
||||
/* state */
|
||||
off_t logical_offset; /* offset that corresponds to physical_offset */
|
||||
off_t physical_offset; /* actual file offset */
|
||||
off_t next_block_offset; /* physical offset of the next block start */
|
||||
off_t last_offset; /* physical offset of where the last block ended */
|
||||
size_t current_data_size;
|
||||
size_t current_consumed_size;
|
||||
|
||||
size_t total_size; /* size of the resulting XMA data */
|
||||
} awc_xma_io_data;
|
||||
|
||||
|
||||
static size_t get_block_header_size(STREAMFILE *streamFile, off_t offset, awc_xma_io_data *data);
|
||||
static size_t get_repeated_data_size(STREAMFILE *streamFile, off_t new_offset, off_t last_offset);
|
||||
static size_t get_block_skip_count(STREAMFILE *streamFile, off_t offset, int channel);
|
||||
|
||||
/* Reads plain XMA data of a single stream. Each block has a header and channels have different num_samples/frames.
|
||||
* Channel data is separate within the block (first all frames of ch0, then ch1, etc), padded, and sometimes
|
||||
* the last few frames of a channel are repeated in the new block (marked with the "discard samples" field). */
|
||||
static size_t awc_xma_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, awc_xma_io_data* data) {
|
||||
size_t total_read = 0;
|
||||
size_t frame_size = 0x800;
|
||||
|
||||
/* ignore bad reads */
|
||||
if (offset < 0 || offset > data->total_size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* previous offset: re-start as we can't map logical<>physical offsets
|
||||
* (kinda slow as it trashes buffers, but shouldn't happen often) */
|
||||
if (offset < data->logical_offset) {
|
||||
data->logical_offset = 0x00;
|
||||
data->physical_offset = data->stream_offset;
|
||||
data->next_block_offset = 0;
|
||||
data->last_offset = 0;
|
||||
data->current_data_size = 0;
|
||||
data->current_consumed_size = 0;
|
||||
}
|
||||
|
||||
/* read from block, moving to next when all data is consumed */
|
||||
while (length > 0) {
|
||||
size_t to_read, bytes_read;
|
||||
|
||||
/* new block */
|
||||
if (data->current_data_size == 0) {
|
||||
size_t header_size = get_block_header_size(streamfile, data->physical_offset, data);
|
||||
/* header table entries = frames... I hope */
|
||||
size_t skip_size = get_block_skip_count(streamfile, data->physical_offset, data->channel) * frame_size;
|
||||
//size_t skip_size = read_32bitBE(data->physical_offset + 0x10*data->channel + 0x00, streamfile) * frame_size;
|
||||
size_t data_size = read_32bitBE(data->physical_offset + 0x10*data->channel + 0x04, streamfile) * frame_size;
|
||||
size_t repeat_samples = read_32bitBE(data->physical_offset + 0x10*data->channel + 0x08, streamfile);
|
||||
size_t repeat_size = 0;
|
||||
|
||||
/* if there are repeat samples current block repeats some frames from last block, find out size */
|
||||
if (repeat_samples && data->last_offset) {
|
||||
off_t data_offset = data->physical_offset + header_size + skip_size;
|
||||
repeat_size = get_repeated_data_size(streamfile, data_offset, data->last_offset);
|
||||
}
|
||||
|
||||
data->next_block_offset = data->physical_offset + data->chunk_size;
|
||||
data->physical_offset += header_size + skip_size + repeat_size; /* data start */
|
||||
data->current_data_size = data_size - repeat_size; /* readable max in this block */
|
||||
data->current_consumed_size = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* block end, go next */
|
||||
if (data->current_consumed_size == data->current_data_size) {
|
||||
data->last_offset = data->physical_offset; /* where last block ended */
|
||||
data->physical_offset = data->next_block_offset;
|
||||
data->current_data_size = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* requested offset is further along, pretend we consumed data and try again */
|
||||
if (offset > data->logical_offset) {
|
||||
size_t to_consume = offset - data->logical_offset;
|
||||
if (to_consume > data->current_data_size - data->current_consumed_size)
|
||||
to_consume = data->current_data_size - data->current_consumed_size;
|
||||
|
||||
data->physical_offset += to_consume;
|
||||
data->logical_offset += to_consume;
|
||||
data->current_consumed_size += to_consume;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* clamp reads up to this block's end */
|
||||
to_read = (data->current_data_size - data->current_consumed_size);
|
||||
if (to_read > length)
|
||||
to_read = length;
|
||||
if (to_read == 0)
|
||||
return total_read; /* should never happen... */
|
||||
|
||||
/* finally read and move buffer/offsets */
|
||||
bytes_read = read_streamfile(dest, data->physical_offset, to_read, streamfile);
|
||||
total_read += bytes_read;
|
||||
if (bytes_read != to_read)
|
||||
return total_read; /* couldn't read fully */
|
||||
|
||||
dest += bytes_read;
|
||||
offset += bytes_read;
|
||||
length -= bytes_read;
|
||||
|
||||
data->physical_offset += bytes_read;
|
||||
data->logical_offset += bytes_read;
|
||||
data->current_consumed_size += bytes_read;
|
||||
}
|
||||
|
||||
return total_read;
|
||||
}
|
||||
|
||||
static size_t awc_xma_io_size(STREAMFILE *streamfile, awc_xma_io_data* data) {
|
||||
off_t physical_offset, max_physical_offset, last_offset;
|
||||
size_t frame_size = 0x800;
|
||||
size_t total_size = 0;
|
||||
|
||||
if (data->total_size)
|
||||
return data->total_size;
|
||||
|
||||
physical_offset = data->stream_offset;
|
||||
max_physical_offset = data->stream_offset + data->stream_size;
|
||||
last_offset = 0;
|
||||
|
||||
/* read blocks and sum final size */
|
||||
while (physical_offset < max_physical_offset) {
|
||||
size_t header_size = get_block_header_size(streamfile, physical_offset, data);
|
||||
/* header table entries = frames... I hope */
|
||||
size_t skip_size = get_block_skip_count(streamfile, physical_offset, data->channel) * frame_size;
|
||||
//size_t skip_size = read_32bitBE(physical_offset + 0x10*data->channel + 0x00, streamfile) * frame_size;
|
||||
size_t data_size = read_32bitBE(physical_offset + 0x10*data->channel + 0x04, streamfile) * frame_size;
|
||||
size_t repeat_samples = read_32bitBE(physical_offset + 0x10*data->channel + 0x08, streamfile);
|
||||
size_t repeat_size = 0;
|
||||
|
||||
/* if there are repeat samples current block repeats some frames from last block, find out size */
|
||||
if (repeat_samples && last_offset) {
|
||||
off_t data_offset = physical_offset + header_size + skip_size;
|
||||
repeat_size = get_repeated_data_size(streamfile, data_offset, last_offset);
|
||||
}
|
||||
|
||||
last_offset = physical_offset + header_size + skip_size + data_size;
|
||||
total_size += data_size - repeat_size;
|
||||
physical_offset += data->chunk_size;
|
||||
}
|
||||
|
||||
data->total_size = total_size;
|
||||
return data->total_size;
|
||||
}
|
||||
|
||||
|
||||
/* Prepares custom IO for AWC XMA, which is interleaved XMA in AWC blocks */
|
||||
static STREAMFILE* setup_awc_xma_streamfile(STREAMFILE *streamFile, off_t stream_offset, size_t stream_size, size_t chunk_size, int channel_count, int channel) {
|
||||
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||
awc_xma_io_data io_data = {0};
|
||||
size_t io_data_size = sizeof(awc_xma_io_data);
|
||||
|
||||
io_data.stream_offset = stream_offset;
|
||||
io_data.stream_size = stream_size;
|
||||
io_data.chunk_size = chunk_size;
|
||||
io_data.channel_count = channel_count;
|
||||
io_data.channel = channel;
|
||||
io_data.physical_offset = stream_offset;
|
||||
|
||||
/* setup subfile */
|
||||
new_streamFile = open_wrap_streamfile(streamFile);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, awc_xma_io_read,awc_xma_io_size);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
//todo maybe should force to read filesize once
|
||||
return temp_streamFile;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* block header size, aligned/padded to 0x800 */
|
||||
static size_t get_block_header_size(STREAMFILE *streamFile, off_t offset, awc_xma_io_data *data) {
|
||||
size_t header_size = 0;
|
||||
int i;
|
||||
int entries = data->channel_count;
|
||||
|
||||
for (i = 0; i < entries; i++) {
|
||||
header_size += 0x10;
|
||||
header_size += read_32bitBE(offset + 0x10*i + 0x04, streamFile) * 0x04; /* entries in the table */
|
||||
}
|
||||
|
||||
if (header_size % 0x800) /* padded */
|
||||
header_size += 0x800 - (header_size % 0x800);
|
||||
|
||||
return header_size;
|
||||
}
|
||||
|
||||
|
||||
/* find data that repeats in the beginning of a new block at the end of last block */
|
||||
static size_t get_repeated_data_size(STREAMFILE *streamFile, off_t new_offset, off_t last_offset) {
|
||||
uint8_t new_frame[0x800];/* buffer to avoid fseek back and forth */
|
||||
size_t frame_size = 0x800;
|
||||
off_t offset;
|
||||
int i;
|
||||
|
||||
/* read block first frame */
|
||||
if (read_streamfile(new_frame,new_offset, frame_size,streamFile) != frame_size)
|
||||
goto fail;
|
||||
|
||||
/* find the frame in last bytes of prev block */
|
||||
offset = last_offset - 0x4000; /* typical max is 1 frame of ~0x800, no way to know exact size */
|
||||
while (offset < last_offset) {
|
||||
/* compare frame vs prev block data */
|
||||
for (i = 0; i < frame_size; i++) {
|
||||
if ((uint8_t)read_8bit(offset+i,streamFile) != new_frame[i])
|
||||
break;
|
||||
}
|
||||
|
||||
/* frame fully compared? */
|
||||
if (i == frame_size)
|
||||
return last_offset - offset;
|
||||
else
|
||||
offset += i+1;
|
||||
}
|
||||
|
||||
fail:
|
||||
VGM_LOG("AWC: can't find repeat size, new=0x%08lx, last=0x%08lx\n", new_offset, last_offset);
|
||||
return 0; /* keep on truckin' */
|
||||
}
|
||||
|
||||
/* header has a skip value, but somehow it's sometimes bigger than expected (WHY!?!?) so just sum all */
|
||||
static size_t get_block_skip_count(STREAMFILE *streamFile, off_t offset, int channel) {
|
||||
size_t skip_count = 0;
|
||||
int i;
|
||||
|
||||
//skip_size = read_32bitBE(offset + 0x10*channel + 0x00, streamFile); /* wrong! */
|
||||
for (i = 0; i < channel; i++) {
|
||||
skip_count += read_32bitBE(offset + 0x10*i + 0x04, streamFile); /* number of frames of this channel */
|
||||
}
|
||||
|
||||
return skip_count;
|
||||
}
|
||||
|
||||
|
||||
#endif /* _AWC_XMA_STREAMFILE_H_ */
|
@ -244,7 +244,7 @@ static STREAMFILE* setup_bgw_atrac3_streamfile(STREAMFILE *streamFile, off_t sub
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, bgw_decryption_read);
|
||||
new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, bgw_decryption_read,NULL);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
|
@ -92,7 +92,7 @@ VGMSTREAM * init_vgmstream_dc_dcsw_dcs(STREAMFILE *streamFile) {
|
||||
vgmstream->interleave_block_size = 0x4000;
|
||||
}
|
||||
|
||||
vgmstream->coding_type = coding_AICA;
|
||||
vgmstream->coding_type = coding_AICA_int;
|
||||
vgmstream->meta_type = meta_DC_DCSW_DCS;
|
||||
|
||||
/* open the file for reading by each channel */
|
||||
|
@ -39,7 +39,7 @@ VGMSTREAM * init_vgmstream_dc_str(STREAMFILE *streamFile) {
|
||||
/* fill in the vital statistics */
|
||||
switch (samples) {
|
||||
case 4:
|
||||
vgmstream->coding_type = coding_AICA;
|
||||
vgmstream->coding_type = coding_AICA_int;
|
||||
vgmstream->num_samples = read_32bitLE(0x14,streamFile);
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = 0;
|
||||
|
@ -103,23 +103,23 @@ static int get_falcom_looping(STREAMFILE *streamFile, int *out_loop_start, int *
|
||||
|
||||
|
||||
/* try one of the many loop files */
|
||||
if ((streamText = open_stream_name(streamFile,"bgm.tbl")) != NULL) {
|
||||
if ((streamText = open_streamfile_by_filename(streamFile,"bgm.tbl")) != NULL) {
|
||||
type = XANADU_NEXT;
|
||||
}
|
||||
else if ((streamText = open_stream_name(streamFile,"bgm.scr")) != NULL) {
|
||||
else if ((streamText = open_streamfile_by_filename(streamFile,"bgm.scr")) != NULL) {
|
||||
type = ZWEI;
|
||||
}
|
||||
else if ((streamText = open_stream_name(streamFile,"loop.txt")) != NULL) { /* actual name in Shift JIS, 0x838B815B8376 */
|
||||
else if ((streamText = open_streamfile_by_filename(streamFile,"loop.txt")) != NULL) { /* actual name in Shift JIS, 0x838B815B8376 */
|
||||
type = DINOSAUR_RESURRECTION;
|
||||
}
|
||||
else if ((streamText = open_stream_name(streamFile,"map.itm")) != NULL) {
|
||||
else if ((streamText = open_streamfile_by_filename(streamFile,"map.itm")) != NULL) {
|
||||
type = GURUMIN;
|
||||
}
|
||||
else {
|
||||
goto end;
|
||||
}
|
||||
|
||||
get_streamfile_name(streamFile,filename,TXT_LINE_MAX);
|
||||
get_streamfile_filename(streamFile,filename,TXT_LINE_MAX);
|
||||
|
||||
/* read line by line */
|
||||
while (txt_offset < get_streamfile_size(streamText)) {
|
||||
|
@ -35,7 +35,7 @@ VGMSTREAM * init_vgmstream_dsp_bdsp(STREAMFILE *streamFile) {
|
||||
#endif
|
||||
|
||||
|
||||
vgmstream->layout_type = layout_dsp_bdsp_blocked;
|
||||
vgmstream->layout_type = layout_blocked_bdsp;
|
||||
vgmstream->interleave_block_size = 0x8;
|
||||
vgmstream->meta_type = meta_DSP_BDSP;
|
||||
|
||||
@ -64,17 +64,17 @@ VGMSTREAM * init_vgmstream_dsp_bdsp(STREAMFILE *streamFile) {
|
||||
|
||||
/* Calc num_samples */
|
||||
start_offset = 0x0;
|
||||
dsp_bdsp_block_update(start_offset,vgmstream);
|
||||
block_update_bdsp(start_offset,vgmstream);
|
||||
vgmstream->num_samples=0;
|
||||
|
||||
do
|
||||
{
|
||||
vgmstream->num_samples += vgmstream->current_block_size*14/8;
|
||||
dsp_bdsp_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
block_update_bdsp(vgmstream->next_block_offset,vgmstream);
|
||||
}
|
||||
while (vgmstream->next_block_offset<get_streamfile_size(streamFile));
|
||||
|
||||
dsp_bdsp_block_update(start_offset,vgmstream);
|
||||
block_update_bdsp(start_offset,vgmstream);
|
||||
|
||||
|
||||
return vgmstream;
|
||||
|
@ -35,11 +35,11 @@ VGMSTREAM * init_vgmstream_ea_1snh(STREAMFILE *streamFile) {
|
||||
ea_header ea = {0};
|
||||
|
||||
|
||||
/* check extension (.asf/as4: common, cnk: some PS games) */
|
||||
if (!check_extensions(streamFile,"asf,as4,cnk"))
|
||||
/* checks */
|
||||
/* .asf/as4: common, cnk: some PS games, .sng: fake for plugins (to mimic EA SCHl's common extension) */
|
||||
if (!check_extensions(streamFile,"asf,as4,cnk,sng"))
|
||||
goto fail;
|
||||
|
||||
/* check header (first block) */
|
||||
if (read_32bitBE(0x00,streamFile) != 0x31534E68 && /* "1SNh" */
|
||||
read_32bitBE(0x00,streamFile) != 0x53454144) /* "SEAD" */
|
||||
goto fail;
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "meta.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "ea_eaac_eatrax_streamfile.h"
|
||||
|
||||
/* EAAudioCore formats, EA's current audio middleware */
|
||||
|
||||
@ -29,7 +30,7 @@ VGMSTREAM * init_vgmstream_ea_snr_sns(STREAMFILE * streamFile) {
|
||||
if (!vgmstream) goto fail;
|
||||
}
|
||||
else {
|
||||
streamData = open_stream_ext(streamFile,"sns");
|
||||
streamData = open_streamfile_by_ext(streamFile,"sns");
|
||||
if (!streamData) goto fail;
|
||||
|
||||
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, streamData, 0x00, 0x00, meta_EA_SNR_SNS);
|
||||
@ -114,6 +115,7 @@ fail:
|
||||
* Some .SNR include stream data, while .SPS have headers so .SPH is optional. */
|
||||
static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, STREAMFILE * streamData, off_t header_offset, off_t start_offset, meta_t meta_type) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
STREAMFILE* temp_streamFile = NULL;
|
||||
int channel_count, loop_flag = 0, version, codec, channel_config, sample_rate, flags;
|
||||
uint32_t num_samples, loop_start = 0, loop_end = 0;
|
||||
|
||||
@ -234,22 +236,28 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
|
||||
/* DSP coefs are read in the blocks */
|
||||
break;
|
||||
|
||||
#if 0 //todo buffered ATRAC9
|
||||
#ifdef VGM_USE_ATRAC9
|
||||
case 0x0a: { /* EATrax */
|
||||
atrac9_config cfg = {0};
|
||||
size_t total_size;
|
||||
|
||||
cfg.channels = vgmstream->channels;
|
||||
cfg.config_data = read_32bitBE(header_offset + 0x08,streamHead);
|
||||
/* 0x0c: data size without blocks?, 0x10: frame size? (same as config data?) */
|
||||
/* 0x10: frame size? (same as config data?) */
|
||||
total_size = read_32bitLE(header_offset + 0x0c,streamHead); /* actual data size without blocks, LE b/c why make sense */
|
||||
|
||||
vgmstream->codec_data = init_atrac9(&cfg);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_ATRAC9;
|
||||
vgmstream->layout_type = layout_blocked_ea_sns;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
/* EATrax is "buffered" ATRAC9, uses custom IO since it's kind of complex to add to the decoder */
|
||||
start_offset = 0x00; /* must point to header start */
|
||||
temp_streamFile = setup_eatrax_streamfile(streamData, total_size);
|
||||
if (!temp_streamFile) goto fail;
|
||||
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
case 0x00: /* "NONE" (internal 'codec not set' flag) */
|
||||
@ -266,16 +274,18 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
|
||||
}
|
||||
|
||||
|
||||
/* open the file for reading by each channel */
|
||||
if (!vgmstream_open_stream(vgmstream,streamData,start_offset))
|
||||
if (!vgmstream_open_stream(vgmstream,temp_streamFile ? temp_streamFile : streamData,start_offset))
|
||||
goto fail;
|
||||
|
||||
close_streamfile(temp_streamFile);
|
||||
|
||||
if (vgmstream->layout_type == layout_blocked_ea_sns)
|
||||
block_update_ea_sns(start_offset, vgmstream);
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
127
src/meta/ea_eaac_eatrax_streamfile.h
Normal file
127
src/meta/ea_eaac_eatrax_streamfile.h
Normal file
@ -0,0 +1,127 @@
|
||||
#ifndef _EA_EAAC_EATRAX_STREAMFILE_H_
|
||||
#define _EA_EAAC_EATRAX_STREAMFILE_H_
|
||||
#include "../streamfile.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
/* state */
|
||||
off_t logical_offset; /* offset that corresponds to physical_offset */
|
||||
off_t physical_offset; /* actual file offset */
|
||||
|
||||
size_t total_size; /* size of the resulting substream */
|
||||
} eatrax_io_data;
|
||||
|
||||
|
||||
/* Reads skipping EA's block headers, so the resulting data is smaller than physical data,
|
||||
* and physical_offset is bigger than offset (ex. reads at offset = 0x00 could be at physical_offset = 0x10).
|
||||
* physical/logical_offset should always be at the start of a block and only advance when a block is fully done */
|
||||
static size_t eatrax_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, eatrax_io_data* data) {
|
||||
size_t total_read = 0;
|
||||
|
||||
/* ignore bad reads */
|
||||
if (offset < 0 || offset > data->total_size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* previous offset: re-start as we can't map logical<>physical offsets
|
||||
* (kinda slow as it trashes buffers, but shouldn't happen often) */
|
||||
if (offset < data->logical_offset) {
|
||||
data->physical_offset = 0x00;
|
||||
data->logical_offset = 0x00;
|
||||
}
|
||||
|
||||
/* read doing one EA block at a time */
|
||||
while (length > 0) {
|
||||
size_t to_read, bytes_read;
|
||||
off_t intrablock_offset, intradata_offset;
|
||||
uint32_t block_size, block_flag, data_size;
|
||||
|
||||
block_flag = read_8bit(data->physical_offset+0x00,streamfile);
|
||||
block_size = read_32bitBE(data->physical_offset+0x00,streamfile) & 0x00FFFFFF;
|
||||
data_size = read_32bitBE(data->physical_offset+0x04,streamfile); /* typically block_size - 0x08 */
|
||||
|
||||
|
||||
/* skip header block */
|
||||
if (block_flag == 0x48) {
|
||||
data->physical_offset += block_size;
|
||||
continue;
|
||||
}
|
||||
/* stop on footer block */
|
||||
if (block_flag == 0x45) {
|
||||
data->physical_offset += block_size;
|
||||
return total_read;
|
||||
}
|
||||
/* data block expected */
|
||||
if (block_flag != 0x44) {
|
||||
return total_read;
|
||||
}
|
||||
|
||||
/* requested offset is outside current block, try next */
|
||||
if (offset >= data->logical_offset + data_size) {
|
||||
data->physical_offset += block_size;
|
||||
data->logical_offset += data_size;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* reads could fall in the middle of the block */
|
||||
intradata_offset = offset - data->logical_offset;
|
||||
intrablock_offset = 0x08 + intradata_offset;
|
||||
|
||||
/* clamp reads up to this block's end */
|
||||
to_read = (data_size - intradata_offset);
|
||||
if (to_read > length)
|
||||
to_read = length;
|
||||
if (to_read == 0)
|
||||
return total_read; /* should never happen... */
|
||||
|
||||
/* finally read and move buffer/offsets */
|
||||
bytes_read = read_streamfile(dest, data->physical_offset + intrablock_offset, to_read, streamfile);
|
||||
total_read += bytes_read;
|
||||
if (bytes_read != to_read)
|
||||
return total_read; /* couldn't read fully */
|
||||
|
||||
dest += bytes_read;
|
||||
offset += bytes_read;
|
||||
length -= bytes_read;
|
||||
|
||||
/* block fully read, go next */
|
||||
if (intradata_offset + bytes_read == data_size) {
|
||||
data->physical_offset += block_size;
|
||||
data->logical_offset += data_size;
|
||||
}
|
||||
}
|
||||
|
||||
return total_read;
|
||||
}
|
||||
|
||||
static size_t eatrax_io_size(STREAMFILE *streamfile, eatrax_io_data* data) {
|
||||
return data->total_size;
|
||||
}
|
||||
|
||||
|
||||
/* Prepares custom IO for EATrax, which is simply blocked ATRAC9 data, but blocks
|
||||
* may end in the middle of an ATRAC9 frame, so reads remove their headers */
|
||||
static STREAMFILE* setup_eatrax_streamfile(STREAMFILE *streamFile, size_t total_size) {
|
||||
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||
eatrax_io_data io_data = {0};
|
||||
size_t io_data_size = sizeof(eatrax_io_data);
|
||||
|
||||
io_data.total_size = total_size;
|
||||
|
||||
/* setup subfile */
|
||||
new_streamFile = open_wrap_streamfile(streamFile);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, eatrax_io_read,eatrax_io_size);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
return temp_streamFile;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* _EA_EAAC_STREAMFILE_H_ */
|
@ -92,11 +92,12 @@ VGMSTREAM * init_vgmstream_ea_schl(STREAMFILE *streamFile) {
|
||||
|
||||
/* check header */
|
||||
if (read_32bitBE(0x00,streamFile) != 0x5343486C && /* "SCHl" */
|
||||
read_32bitBE(0x00,streamFile) != 0x5348454E) /* "SHEN" */
|
||||
read_32bitBE(0x00,streamFile) != 0x5348454E && /* "SHEN" */
|
||||
read_32bitBE(0x00,streamFile) != 0x53484652) /* "SHFR" */
|
||||
goto fail;
|
||||
|
||||
/* stream is divided into blocks/chunks: SCHl=audio header, SCCl=count of SCDl, SCDl=data xN, SCLl=loop end, SCEl=end.
|
||||
* Video uses various blocks (MVhd/MV0K/etc) and sometimes alt audio blocks (SHEN/SDEN/SEEN).
|
||||
* Video uses various blocks (MVhd/MV0K/etc) and sometimes alt audio blocks (SHxx/SCxx/SDxx/SExx where XX=language, EN/FR).
|
||||
* The number/size is affected by: block rate setting, sample rate, channels, CPU location (SPU/main/DSP/others), etc */
|
||||
|
||||
header_size = read_32bitLE(0x04,streamFile);
|
||||
@ -769,7 +770,7 @@ static int get_ea_stream_total_samples(STREAMFILE* streamFile, off_t start_offse
|
||||
|
||||
block_samples = 0;
|
||||
|
||||
if (id == 0x5343446C || id == 0x5344454E) { /* "SCDl" "SDEN" audio data */
|
||||
if (id == 0x5343446C || id == 0x5344454E || id == 0x53444652) { /* "SCDl" "SDEN" "SDFR" audio data */
|
||||
switch (ea->codec2) {
|
||||
case EA_CODEC2_VAG:
|
||||
block_samples = ps_bytes_to_samples(block_size-0x10, ea->channels);
|
||||
@ -785,7 +786,7 @@ static int get_ea_stream_total_samples(STREAMFILE* streamFile, off_t start_offse
|
||||
block_size = 0x04;
|
||||
}
|
||||
|
||||
if (id == 0x5343486C || id == 0x5348454E) { /* "SCHl" "SHEN" end block */
|
||||
if (id == 0x5343486C || id == 0x5348454E || id == 0x53484652) { /* "SCHl" "SHEN" "SHFR" end block */
|
||||
new_schl = 1;
|
||||
}
|
||||
}
|
||||
@ -800,8 +801,8 @@ static int get_ea_stream_total_samples(STREAMFILE* streamFile, off_t start_offse
|
||||
num_samples += block_samples;
|
||||
block_offset += block_size;
|
||||
|
||||
/* "SCEl" are aligned to 0x80 usually, but causes problems if not 32b-aligned (ex. Need for Speed 2 PC) */
|
||||
if ((id == 0x5343456C || id == 0x5345454E) && block_offset % 0x04) {
|
||||
/* "SCEl" "SEEN" "SEFR" are aligned to 0x80 usually, but causes problems if not 32b-aligned (ex. Need for Speed 2 PC) */
|
||||
if ((id == 0x5343456C || id == 0x5345454E || id == 0x53454652) && block_offset % 0x04) {
|
||||
VGM_LOG_ONCE("EA SCHl: mis-aligned end offset found\n");
|
||||
block_offset += 0x04 - (block_offset % 0x04);
|
||||
}
|
||||
@ -832,10 +833,10 @@ static off_t get_ea_stream_mpeg_start_offset(STREAMFILE* streamFile, off_t start
|
||||
if (block_size > 0x00F00000) /* size is always LE, except in early SAT/MAC */
|
||||
block_size = read_32bitBE(block_offset+0x04,streamFile);
|
||||
|
||||
if (id == 0x5343446C) { /* "SCDl" data block found */
|
||||
if (id == 0x5343446C || id == 0x5344454E || id == 0x53444652) { /* "SCDl/SDEN/SDFR" data block found */
|
||||
off_t offset = read_32bit(block_offset+0x0c,streamFile); /* first value seems ok, second is something else in EALayer3 */
|
||||
return block_offset + 0x0c + ea->channels*0x04 + offset;
|
||||
} else if (id == 0x5343436C) { /* "SCCl" data count found */
|
||||
} else if (id == 0x5343436C || id == 0x5343454E || id == 0x53434652) { /* "SCCl/SCEN/SCFR" data count found */
|
||||
block_offset += block_size; /* size includes header */
|
||||
continue;
|
||||
} else {
|
||||
|
56
src/meta/ea_wve_ad10.c
Normal file
56
src/meta/ea_wve_ad10.c
Normal file
@ -0,0 +1,56 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../layout/layout.h"
|
||||
|
||||
/* EA WVE (Ad10) - from Electronic Arts PS movies [Wing Commander 3/4 (PS)] */
|
||||
VGMSTREAM * init_vgmstream_ea_wve_ad10(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag, channel_count;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "wve"))
|
||||
goto fail;
|
||||
|
||||
start_offset = 0x00;
|
||||
if (read_32bitBE(start_offset, streamFile) != 0x41643130 && /* "Ad10" */
|
||||
read_32bitBE(start_offset, streamFile) != 0x41643131) /* "Ad11" (last block, but could be first) */
|
||||
goto fail;
|
||||
loop_flag = 0;
|
||||
/* no header = no channels, but seems if the first PS-ADPCM header is 00 then it's mono, somehow
|
||||
* (ex. Wing Commander 3 intro / Wing Commander 4 = stereo, rest of Wing Commander 3 = mono) */
|
||||
channel_count = read_8bit(start_offset+0x08,streamFile) != 0 ? 2 : 1;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = 22050;
|
||||
vgmstream->meta_type = meta_EA_WVE_AD10;
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_blocked_ea_wve_ad10;
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
|
||||
/* calc num_samples manually */
|
||||
{
|
||||
vgmstream->num_samples = 0;
|
||||
block_update_ea_wve_ad10(start_offset,vgmstream);
|
||||
do {
|
||||
vgmstream->num_samples += ps_bytes_to_samples(vgmstream->current_block_size, 1);
|
||||
block_update_ea_wve_ad10(vgmstream->next_block_offset,vgmstream);
|
||||
}
|
||||
while (vgmstream->next_block_offset < get_streamfile_size(streamFile));
|
||||
}
|
||||
|
||||
block_update_ea_wve_ad10(start_offset, vgmstream);
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
61
src/meta/ea_wve_au00.c
Normal file
61
src/meta/ea_wve_au00.c
Normal file
@ -0,0 +1,61 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../layout/layout.h"
|
||||
|
||||
/* EA WVE (VLC0/au00) - from Electronic Arts PS movies [Future Cop - L.A.P.D. (PS), Supercross 2000 (PS)] */
|
||||
VGMSTREAM * init_vgmstream_ea_wve_au00(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag, channel_count;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "wve"))
|
||||
goto fail;
|
||||
if (read_32bitBE(0x00,streamFile) != 0x564C4330) /* "VLC0" */
|
||||
goto fail;
|
||||
|
||||
start_offset = read_32bitBE(0x04,streamFile);
|
||||
if (read_32bitBE(start_offset, streamFile) != 0x61753030 && /* "au00" */
|
||||
read_32bitBE(start_offset, streamFile) != 0x61753031) /* "au01" (last block, but could be first) */
|
||||
goto fail;
|
||||
loop_flag = 0;
|
||||
channel_count = 2;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = 22050;
|
||||
vgmstream->meta_type = meta_EA_WVE_AU00;
|
||||
|
||||
/* You'd think they'd use coding_EA_XA_int but instead it's PS-ADPCM without flags and 0x0f frame size
|
||||
* (equivalent to configurable PS-ADPCM), surely to shoehorn EA-XA sizes into the PS1 hardware decoder */
|
||||
vgmstream->coding_type = coding_PSX_cfg;
|
||||
vgmstream->interleave_block_size = 0x0f;
|
||||
vgmstream->layout_type = layout_blocked_ea_wve_au00;
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
|
||||
/* calc num_samples manually */
|
||||
{
|
||||
vgmstream->num_samples = 0;
|
||||
block_update_ea_wve_au00(start_offset,vgmstream);
|
||||
do {
|
||||
/* ps_cfg_bytes_to_samples */
|
||||
vgmstream->num_samples += vgmstream->current_block_size / vgmstream->interleave_block_size*channel_count * 28 / channel_count;
|
||||
block_update_ea_wve_au00(vgmstream->next_block_offset,vgmstream);
|
||||
}
|
||||
while (vgmstream->next_block_offset < get_streamfile_size(streamFile));
|
||||
}
|
||||
|
||||
block_update_ea_wve_au00(start_offset, vgmstream);
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
@ -44,7 +44,7 @@ VGMSTREAM * init_vgmstream_emff_ps2(STREAMFILE *streamFile) {
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
|
||||
vgmstream->layout_type = layout_emff_ps2_blocked;
|
||||
vgmstream->layout_type = layout_blocked_emff_ps2;
|
||||
vgmstream->interleave_block_size = 0x10;
|
||||
vgmstream->meta_type = meta_EMFF_PS2;
|
||||
|
||||
@ -59,7 +59,7 @@ VGMSTREAM * init_vgmstream_emff_ps2(STREAMFILE *streamFile) {
|
||||
}
|
||||
|
||||
/* Calc num_samples */
|
||||
emff_ps2_block_update(start_offset,vgmstream);
|
||||
block_update_emff_ps2(start_offset,vgmstream);
|
||||
vgmstream->num_samples = read_32bitLE(0x8,streamFile);
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = (read_32bitLE(0x28,streamFile)-start_offset)*28/16/channel_count;
|
||||
@ -148,7 +148,7 @@ VGMSTREAM * init_vgmstream_emff_ngc(STREAMFILE *streamFile) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
vgmstream->layout_type = layout_emff_ngc_blocked;
|
||||
vgmstream->layout_type = layout_blocked_emff_ngc;
|
||||
vgmstream->interleave_block_size = 0x10;
|
||||
vgmstream->meta_type = meta_EMFF_NGC;
|
||||
|
||||
@ -163,7 +163,7 @@ VGMSTREAM * init_vgmstream_emff_ngc(STREAMFILE *streamFile) {
|
||||
}
|
||||
|
||||
/* Calc num_samples */
|
||||
emff_ngc_block_update(start_offset,vgmstream);
|
||||
block_update_emff_ngc(start_offset,vgmstream);
|
||||
vgmstream->num_samples = read_32bitBE(0x8,streamFile);;
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = (read_32bitBE(0x28,streamFile))*14/8/channel_count;
|
||||
|
@ -3,6 +3,8 @@
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
|
||||
static int read_pos_file(uint8_t * buf, size_t bufsize, STREAMFILE *streamFile);
|
||||
|
||||
/**
|
||||
* Generic init FFmpeg and vgmstream for any file supported by FFmpeg.
|
||||
* Called by vgmstream when trying to identify the file type (if the player allows it).
|
||||
@ -75,4 +77,47 @@ fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* open file containing looping data and copy to buffer
|
||||
*
|
||||
* returns true if found and copied
|
||||
*/
|
||||
int read_pos_file(uint8_t * buf, size_t bufsize, STREAMFILE *streamFile) {
|
||||
char posname[PATH_LIMIT];
|
||||
char filename[PATH_LIMIT];
|
||||
/*size_t bytes_read;*/
|
||||
STREAMFILE * streamFilePos= NULL;
|
||||
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
|
||||
if (strlen(filename)+4 > sizeof(posname)) goto fail;
|
||||
|
||||
/* try to open a posfile using variations: "(name.ext).pos" */
|
||||
{
|
||||
strcpy(posname, filename);
|
||||
strcat(posname, ".pos");
|
||||
streamFilePos = streamFile->open(streamFile,posname,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (streamFilePos) goto found;
|
||||
|
||||
goto fail;
|
||||
}
|
||||
|
||||
found:
|
||||
//if (get_streamfile_size(streamFilePos) != bufsize) goto fail;
|
||||
|
||||
/* allow pos files to be of different sizes in case of new features, just fill all we can */
|
||||
memset(buf, 0, bufsize);
|
||||
read_streamfile(buf, 0, bufsize, streamFilePos);
|
||||
|
||||
close_streamfile(streamFilePos);
|
||||
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
if (streamFilePos) close_streamfile(streamFilePos);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -146,7 +146,7 @@ static STREAMFILE* setup_fsb_streamfile(STREAMFILE *streamFile, const uint8_t *
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, fsb_decryption_read);
|
||||
new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, fsb_decryption_read,NULL);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
|
@ -157,6 +157,8 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) {
|
||||
coding = coding_DVI_IMA_int;
|
||||
if (coding == coding_IMA)
|
||||
coding = coding_IMA_int;
|
||||
if (coding == coding_AICA)
|
||||
coding = coding_AICA_int;
|
||||
}
|
||||
|
||||
/* to avoid endless loops */
|
||||
@ -173,7 +175,7 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) {
|
||||
}
|
||||
|
||||
/* setup adpcm */
|
||||
if (coding == coding_AICA) {
|
||||
if (coding == coding_AICA || coding == coding_AICA_int) {
|
||||
int i;
|
||||
for (i=0;i<vgmstream->channels;i++) {
|
||||
vgmstream->ch[i].adpcm_step_index = 0x7f;
|
||||
|
@ -16,7 +16,7 @@ VGMSTREAM * init_vgmstream_gsp_gsb(STREAMFILE *streamFile) {
|
||||
if (!check_extensions(streamFile,"gsb"))
|
||||
goto fail;
|
||||
|
||||
streamFileGSP = open_stream_ext(streamFile, "gsp");
|
||||
streamFileGSP = open_streamfile_by_ext(streamFile, "gsp");
|
||||
if (!streamFileGSP) goto fail;
|
||||
|
||||
/* check header */
|
||||
@ -63,7 +63,7 @@ VGMSTREAM * init_vgmstream_gsp_gsb(STREAMFILE *streamFile) {
|
||||
size_t num_blocks;
|
||||
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_gsb_blocked;
|
||||
vgmstream->layout_type = layout_blocked_gsb;
|
||||
|
||||
if (!find_chunk_be(streamFileGSP, 0x47434558,first_offset,1, &chunk_offset,NULL)) goto fail; /*"GCEX"*/
|
||||
|
||||
|
@ -91,7 +91,7 @@ VGMSTREAM * init_vgmstream_halpst(STREAMFILE *streamFile) {
|
||||
}
|
||||
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_halpst_blocked;
|
||||
vgmstream->layout_type = layout_blocked_halpst;
|
||||
vgmstream->meta_type = meta_HALPST;
|
||||
|
||||
/* load decode coefs */
|
||||
@ -120,7 +120,7 @@ VGMSTREAM * init_vgmstream_halpst(STREAMFILE *streamFile) {
|
||||
}
|
||||
|
||||
/* start me up */
|
||||
halpst_block_update(header_length,vgmstream);
|
||||
block_update_halpst(header_length,vgmstream);
|
||||
|
||||
return vgmstream;
|
||||
|
||||
|
@ -285,6 +285,7 @@ VGMSTREAM * init_vgmstream_psx_fag(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ps2_mihb(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ngc_pdt_split(STREAMFILE * streamFile);
|
||||
VGMSTREAM * init_vgmstream_ngc_pdt(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_wii_mus(STREAMFILE * streamFile);
|
||||
@ -717,4 +718,16 @@ VGMSTREAM * init_vgmstream_smv(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_nxap(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ea_wve_au00(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ea_wve_ad10(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_sthd(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ngc_dsp_std_le(STREAMFILE *streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_pcm_sre(STREAMFILE *streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_dsp_mcadpcm(STREAMFILE *streamFile);
|
||||
|
||||
#endif /*_META_H*/
|
||||
|
@ -240,7 +240,7 @@ VGMSTREAM * init_vgmstream_mp4_aac_ffmpeg(STREAMFILE *streamFile) {
|
||||
vgmstream->codec_data = ffmpeg_data;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->meta_type = meta_FFmpeg;
|
||||
vgmstream->meta_type = meta_MP4;
|
||||
|
||||
vgmstream->num_samples = ffmpeg_data->totalSamples;
|
||||
vgmstream->sample_rate = ffmpeg_data->sampleRate;
|
||||
|
@ -31,7 +31,7 @@ VGMSTREAM * init_vgmstream_naomi_adpcm(STREAMFILE *streamFile) {
|
||||
start_offset = 0x40;
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = 44100;
|
||||
vgmstream->coding_type = coding_AICA;
|
||||
vgmstream->coding_type = coding_AICA_int;
|
||||
vgmstream->num_samples = (get_streamfile_size(streamFile)-start_offset);
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = 0;
|
||||
|
@ -1,48 +1,105 @@
|
||||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* SPSD - Naomi GD-ROM streams [Guilty Gear X (Naomi), Crazy Taxi (Naomi), Virtua Tennis 2 (Naomi)] */
|
||||
/* SPSD - Naomi (arcade) streams [Guilty Gear X (Naomi), Crazy Taxi (Naomi), Virtua Tennis 2 (Naomi)] */
|
||||
VGMSTREAM * init_vgmstream_naomi_spsd(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
size_t data_size;
|
||||
int loop_flag, channel_count;
|
||||
int loop_flag, channel_count, codec, flags, index;
|
||||
|
||||
|
||||
/* checks */
|
||||
/* .spsd: header id */
|
||||
if (!check_extensions(streamFile, "spsd"))
|
||||
goto fail;
|
||||
if (read_32bitBE(0x00,streamFile) != 0x53505344) /* "SPSD" */
|
||||
goto fail;
|
||||
|
||||
loop_flag = 0;
|
||||
channel_count = 2;
|
||||
if (read_32bitBE(0x04,streamFile) != 0x01010004 && /* standard version */
|
||||
read_32bitBE(0x04,streamFile) != 0x00010004) /* uncommon version [Crazy Taxi (Naomi)] */
|
||||
goto fail;
|
||||
|
||||
|
||||
codec = read_8bit(0x08,streamFile);
|
||||
flags = read_8bit(0x09,streamFile);
|
||||
index = read_16bitLE(0x0a,streamFile);
|
||||
data_size = read_32bitLE(0x0c,streamFile);
|
||||
//if (data_size + start_offset != get_streamfile_size(streamFile))
|
||||
// goto fail; /* some rips out there have incorrect padding */
|
||||
|
||||
//todo with 0x80 seems 0x2c is a loop_start_sample but must be adjusted to +1 block? (uncommon flag though)
|
||||
loop_flag = (flags & 0x80);
|
||||
channel_count = ((flags & 0x01) || (flags & 0x02)) ? 2 : 1; /* 0x02 is rare but looks normal (Virtua Tennis 2) */
|
||||
start_offset = 0x40;
|
||||
data_size = get_streamfile_size(streamFile) - start_offset;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = (uint16_t)read_16bitLE(0x2A,streamFile);
|
||||
vgmstream->num_samples = read_32bitLE(0x0C,streamFile);
|
||||
|
||||
vgmstream->meta_type = meta_NAOMI_SPSD;
|
||||
switch (read_8bit(0x08,streamFile)) {
|
||||
switch (codec) {
|
||||
case 0x00: /* [Virtua Tennis 2 (Naomi), Club Kart - European Session (Naomi)] */
|
||||
vgmstream->coding_type = coding_PCM16LE;
|
||||
vgmstream->num_samples = pcm_bytes_to_samples(data_size,channel_count,16);
|
||||
vgmstream->loop_start_sample = read_32bitLE(0x2c,streamFile) + pcm_bytes_to_samples(0x2000*channel_count,channel_count,16);
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
break;
|
||||
|
||||
case 0x01: /* [Virtua Tennis 2 (Naomi)] */
|
||||
vgmstream->coding_type = coding_PCM8;
|
||||
vgmstream->num_samples = pcm_bytes_to_samples(data_size,channel_count,8);
|
||||
vgmstream->loop_start_sample = read_32bitLE(0x2c,streamFile) + pcm_bytes_to_samples(0x2000*channel_count,channel_count,8);
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
break;
|
||||
case 0x03:
|
||||
vgmstream->coding_type = coding_AICA;
|
||||
|
||||
case 0x03: /* standard */
|
||||
vgmstream->coding_type = coding_AICA_int;
|
||||
vgmstream->num_samples = aica_bytes_to_samples(data_size,channel_count);
|
||||
vgmstream->loop_start_sample = /*read_32bitLE(0x2c,streamFile) +*/ aica_bytes_to_samples(0x2000*channel_count,channel_count);
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
break;
|
||||
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x2000;
|
||||
if (vgmstream->interleave_block_size)
|
||||
vgmstream->interleave_last_block_size = (data_size % (vgmstream->interleave_block_size*vgmstream->channels)) / vgmstream->channels;
|
||||
|
||||
/* interleave index, maybe */
|
||||
switch(index) {
|
||||
case 0x0000:
|
||||
if (channel_count != 1) goto fail;
|
||||
vgmstream->layout_type = layout_none;
|
||||
break;
|
||||
|
||||
case 0x000d:
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x2000;
|
||||
if (vgmstream->interleave_block_size)
|
||||
vgmstream->interleave_last_block_size = (data_size % (vgmstream->interleave_block_size*vgmstream->channels)) / vgmstream->channels;
|
||||
break;
|
||||
|
||||
case 0x00ff:
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = data_size / channel_count;
|
||||
break;
|
||||
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* todo seems to decode slightly incorrectly in after certain data (loop section start?)
|
||||
* may depend on values in 0x20 or 0x2c [ex. Marvel vs Capcom 2 (Naomi)]
|
||||
* at 0x30(4*ch) is some config per channel but doesn't seem to affect ADPCM (found with PCM too) */
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < channel_count; i++) {
|
||||
vgmstream->ch[i].adpcm_step_index = 0x7f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
|
@ -30,32 +30,41 @@ struct dsp_header {
|
||||
};
|
||||
|
||||
/* read the above struct; returns nonzero on failure */
|
||||
static int read_dsp_header(struct dsp_header *header, off_t offset, STREAMFILE *file) {
|
||||
static int read_dsp_header_endian(struct dsp_header *header, off_t offset, STREAMFILE *streamFile, int big_endian) {
|
||||
int32_t (*get_32bit)(uint8_t *) = big_endian ? get_32bitBE : get_32bitLE;
|
||||
int16_t (*get_16bit)(uint8_t *) = big_endian ? get_16bitBE : get_16bitLE;
|
||||
int i;
|
||||
uint8_t buf[0x4e]; /* usually padded out to 0x60 */
|
||||
if (read_streamfile(buf, offset, 0x4e, file) != 0x4e)
|
||||
|
||||
if (read_streamfile(buf, offset, 0x4e, streamFile) != 0x4e)
|
||||
return 1;
|
||||
header->sample_count = get_32bitBE(buf+0x00);
|
||||
header->nibble_count = get_32bitBE(buf+0x04);
|
||||
header->sample_rate = get_32bitBE(buf+0x08);
|
||||
header->loop_flag = get_16bitBE(buf+0x0c);
|
||||
header->format = get_16bitBE(buf+0x0e);
|
||||
header->loop_start_offset = get_32bitBE(buf+0x10);
|
||||
header->loop_end_offset = get_32bitBE(buf+0x14);
|
||||
header->ca = get_32bitBE(buf+0x18);
|
||||
header->sample_count = get_32bit(buf+0x00);
|
||||
header->nibble_count = get_32bit(buf+0x04);
|
||||
header->sample_rate = get_32bit(buf+0x08);
|
||||
header->loop_flag = get_16bit(buf+0x0c);
|
||||
header->format = get_16bit(buf+0x0e);
|
||||
header->loop_start_offset = get_32bit(buf+0x10);
|
||||
header->loop_end_offset = get_32bit(buf+0x14);
|
||||
header->ca = get_32bit(buf+0x18);
|
||||
for (i=0; i < 16; i++)
|
||||
header->coef[i] = get_16bitBE(buf+0x1c+i*0x2);
|
||||
header->gain = get_16bitBE(buf+0x3c);
|
||||
header->initial_ps = get_16bitBE(buf+0x3e);
|
||||
header->initial_hist1 = get_16bitBE(buf+0x40);
|
||||
header->initial_hist2 = get_16bitBE(buf+0x42);
|
||||
header->loop_ps = get_16bitBE(buf+0x44);
|
||||
header->loop_hist1 = get_16bitBE(buf+0x46);
|
||||
header->loop_hist2 = get_16bitBE(buf+0x48);
|
||||
header->channel_count = get_16bitBE(buf+0x4a);
|
||||
header->block_size = get_16bitBE(buf+0x4c);
|
||||
header->coef[i] = get_16bit(buf+0x1c+i*0x02);
|
||||
header->gain = get_16bit(buf+0x3c);
|
||||
header->initial_ps = get_16bit(buf+0x3e);
|
||||
header->initial_hist1 = get_16bit(buf+0x40);
|
||||
header->initial_hist2 = get_16bit(buf+0x42);
|
||||
header->loop_ps = get_16bit(buf+0x44);
|
||||
header->loop_hist1 = get_16bit(buf+0x46);
|
||||
header->loop_hist2 = get_16bit(buf+0x48);
|
||||
header->channel_count = get_16bit(buf+0x4a);
|
||||
header->block_size = get_16bit(buf+0x4c);
|
||||
return 0;
|
||||
}
|
||||
static int read_dsp_header(struct dsp_header *header, off_t offset, STREAMFILE *file) {
|
||||
return read_dsp_header_endian(header, offset, file, 1);
|
||||
}
|
||||
static int read_dsp_header_le(struct dsp_header *header, off_t offset, STREAMFILE *file) {
|
||||
return read_dsp_header_endian(header, offset, file, 0);
|
||||
}
|
||||
|
||||
|
||||
static void setup_vgmstream_dsp(VGMSTREAM* vgmstream, struct dsp_header* ch_header) {
|
||||
@ -71,12 +80,12 @@ static void setup_vgmstream_dsp(VGMSTREAM* vgmstream, struct dsp_header* ch_head
|
||||
}
|
||||
}
|
||||
|
||||
static int dsp_load_header(struct dsp_header* ch_header, int channels, STREAMFILE *streamFile, off_t offset, size_t spacing) {
|
||||
static int dsp_load_header_endian(struct dsp_header* ch_header, int channels, STREAMFILE *streamFile, off_t offset, size_t spacing, int big_endian) {
|
||||
int i;
|
||||
|
||||
/* load standard dsp header per channel */
|
||||
for (i = 0; i < channels; i++) {
|
||||
if (read_dsp_header(&ch_header[i], offset + i*spacing, streamFile))
|
||||
if (read_dsp_header_endian(&ch_header[i], offset + i*spacing, streamFile, big_endian))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@ -84,6 +93,12 @@ static int dsp_load_header(struct dsp_header* ch_header, int channels, STREAMFIL
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
static int dsp_load_header(struct dsp_header* ch_header, int channels, STREAMFILE *streamFile, off_t offset, size_t spacing) {
|
||||
return dsp_load_header_endian(ch_header, channels, streamFile, offset, spacing, 1);
|
||||
}
|
||||
static int dsp_load_header_le(struct dsp_header* ch_header, int channels, STREAMFILE *streamFile, off_t offset, size_t spacing) {
|
||||
return dsp_load_header_endian(ch_header, channels, streamFile, offset, spacing, 0);
|
||||
}
|
||||
static int check_dsp_format(struct dsp_header* ch_header, int channels) {
|
||||
int i;
|
||||
|
||||
@ -149,30 +164,29 @@ fail:
|
||||
|
||||
/* ********************************* */
|
||||
|
||||
/* the standard .dsp, as generated by DSPADPCM.exe */
|
||||
/* .dsp - standard dsp as generated by DSPADPCM.exe */
|
||||
VGMSTREAM * init_vgmstream_ngc_dsp_std(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
|
||||
struct dsp_header header;
|
||||
const off_t start_offset = 0x60;
|
||||
int i;
|
||||
const size_t header_size = 0x60;
|
||||
off_t start_offset;
|
||||
int i, channel_count;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
/* checks */
|
||||
/* .dsp: standard, .adp: Dr. Muto (GC) mono files */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("dsp",filename_extension(filename)) &&
|
||||
strcasecmp("adp", filename_extension(filename))) goto fail;
|
||||
if (!check_extensions(streamFile, "dsp,adp"))
|
||||
goto fail;
|
||||
|
||||
if (read_dsp_header(&header, 0, streamFile)) goto fail;
|
||||
if (read_dsp_header(&header, 0x00, streamFile))
|
||||
goto fail;
|
||||
|
||||
channel_count = 1;
|
||||
start_offset = header_size;
|
||||
|
||||
/* check initial predictor/scale */
|
||||
if (header.initial_ps != (uint8_t)read_8bit(start_offset,streamFile))
|
||||
goto fail;
|
||||
|
||||
/* check type==0 and gain==0 */
|
||||
goto fail; /* check initial predictor/scale */
|
||||
if (header.format || header.gain)
|
||||
goto fail;
|
||||
goto fail; /* check type==0 and gain==0 */
|
||||
|
||||
/* Check for a matching second header. If we find one and it checks
|
||||
* out thoroughly, we're probably not dealing with a genuine mono DSP.
|
||||
@ -180,13 +194,14 @@ VGMSTREAM * init_vgmstream_ngc_dsp_std(STREAMFILE *streamFile) {
|
||||
* predictor/scale check if the first byte is 0 */
|
||||
{
|
||||
struct dsp_header header2;
|
||||
|
||||
read_dsp_header(&header2, 0x60, streamFile);
|
||||
read_dsp_header(&header2, header_size, streamFile);
|
||||
|
||||
if (header.sample_count == header2.sample_count &&
|
||||
header.nibble_count == header2.nibble_count &&
|
||||
header.sample_rate == header2.sample_rate &&
|
||||
header.loop_flag == header2.loop_flag) goto fail;
|
||||
header.loop_flag == header2.loop_flag) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (header.loop_flag) {
|
||||
@ -194,7 +209,7 @@ VGMSTREAM * init_vgmstream_ngc_dsp_std(STREAMFILE *streamFile) {
|
||||
/* check loop predictor/scale */
|
||||
loop_off = header.loop_start_offset/16*8;
|
||||
if (header.loop_ps != (uint8_t)read_8bit(start_offset+loop_off,streamFile)) {
|
||||
/* rarely won't match (ex ESPN 2002), not sure if header or calc problem, but doesn't seem to matter
|
||||
/* rarely won't match (ex ESPN 2002), not sure if header or calc problem, but doesn't seem to matter
|
||||
* (there may be a "click" when looping, or loop values may be too big and loop disabled anyway) */
|
||||
VGM_LOG("DSP (std): bad loop_predictor\n");
|
||||
//header.loop_flag = 0;
|
||||
@ -202,110 +217,162 @@ VGMSTREAM * init_vgmstream_ngc_dsp_std(STREAMFILE *streamFile) {
|
||||
}
|
||||
}
|
||||
|
||||
/* compare num_samples with nibble count */
|
||||
/*
|
||||
fprintf(stderr,"num samples (literal): %d\n",read_32bitBE(0,streamFile));
|
||||
fprintf(stderr,"num samples (nibbles): %d\n",dsp_nibbles_to_samples(read_32bitBE(4,streamFile)));
|
||||
*/
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
|
||||
|
||||
vgmstream = allocate_vgmstream(1,header.loop_flag);
|
||||
vgmstream = allocate_vgmstream(channel_count,header.loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->num_samples = header.sample_count;
|
||||
vgmstream->sample_rate = header.sample_rate;
|
||||
|
||||
vgmstream->loop_start_sample = dsp_nibbles_to_samples(
|
||||
header.loop_start_offset);
|
||||
vgmstream->loop_end_sample = dsp_nibbles_to_samples(
|
||||
header.loop_end_offset)+1;
|
||||
|
||||
/* don't know why, but it does happen*/
|
||||
if (vgmstream->loop_end_sample > vgmstream->num_samples)
|
||||
vgmstream->num_samples = header.sample_count;
|
||||
vgmstream->loop_start_sample = dsp_nibbles_to_samples(header.loop_start_offset);
|
||||
vgmstream->loop_end_sample = dsp_nibbles_to_samples(header.loop_end_offset)+1;
|
||||
if (vgmstream->loop_end_sample > vgmstream->num_samples) /* don't know why, but it does happen */
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
vgmstream->meta_type = meta_DSP_STD;
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->meta_type = meta_DSP_STD;
|
||||
|
||||
/* coeffs */
|
||||
for (i=0;i<16;i++)
|
||||
vgmstream->ch[0].adpcm_coef[i] = header.coef[i];
|
||||
|
||||
/* initial history */
|
||||
/* always 0 that I've ever seen, but for completeness... */
|
||||
vgmstream->ch[0].adpcm_history1_16 = header.initial_hist1;
|
||||
vgmstream->ch[0].adpcm_history2_16 = header.initial_hist2;
|
||||
|
||||
/* open the file for reading */
|
||||
vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
|
||||
if (!vgmstream->ch[0].streamfile) goto fail;
|
||||
|
||||
vgmstream->ch[0].channel_start_offset=
|
||||
vgmstream->ch[0].offset=start_offset;
|
||||
{
|
||||
/* adpcm coeffs/history */
|
||||
for (i = 0; i < 16; i++)
|
||||
vgmstream->ch[0].adpcm_coef[i] = header.coef[i];
|
||||
vgmstream->ch[0].adpcm_history1_16 = header.initial_hist1;
|
||||
vgmstream->ch[0].adpcm_history2_16 = header.initial_hist2;
|
||||
}
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
/* clean up anything we may have opened */
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* the standard multi-channel .dsp, as generated by DSPADPCM.exe */
|
||||
/* .dsp - little endian dsp, possibly main Switch .dsp [LEGO Worlds (Switch)] */
|
||||
VGMSTREAM * init_vgmstream_ngc_dsp_std_le(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
struct dsp_header header;
|
||||
const size_t header_size = 0x60;
|
||||
off_t start_offset;
|
||||
int i, channel_count;
|
||||
|
||||
/* checks */
|
||||
/* .adpcm: LEGO Worlds */
|
||||
if (!check_extensions(streamFile, "adpcm"))
|
||||
goto fail;
|
||||
|
||||
if (read_dsp_header_le(&header, 0x00, streamFile))
|
||||
goto fail;
|
||||
|
||||
channel_count = 1;
|
||||
start_offset = header_size;
|
||||
|
||||
if (header.initial_ps != (uint8_t)read_8bit(start_offset,streamFile))
|
||||
goto fail; /* check initial predictor/scale */
|
||||
if (header.format || header.gain)
|
||||
goto fail; /* check type==0 and gain==0 */
|
||||
|
||||
/* Check for a matching second header. If we find one and it checks
|
||||
* out thoroughly, we're probably not dealing with a genuine mono DSP.
|
||||
* In many cases these will pass all the other checks, including the
|
||||
* predictor/scale check if the first byte is 0 */
|
||||
{
|
||||
struct dsp_header header2;
|
||||
read_dsp_header_le(&header2, header_size, streamFile);
|
||||
|
||||
if (header.sample_count == header2.sample_count &&
|
||||
header.nibble_count == header2.nibble_count &&
|
||||
header.sample_rate == header2.sample_rate &&
|
||||
header.loop_flag == header2.loop_flag) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (header.loop_flag) {
|
||||
off_t loop_off;
|
||||
/* check loop predictor/scale */
|
||||
loop_off = header.loop_start_offset/16*8;
|
||||
if (header.loop_ps != (uint8_t)read_8bit(start_offset+loop_off,streamFile)) {
|
||||
/* rarely won't match (ex ESPN 2002), not sure if header or calc problem, but doesn't seem to matter
|
||||
* (there may be a "click" when looping, or loop values may be too big and loop disabled anyway) */
|
||||
VGM_LOG("DSP (std): bad loop_predictor\n");
|
||||
//header.loop_flag = 0;
|
||||
//goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,header.loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = header.sample_rate;
|
||||
vgmstream->num_samples = header.sample_count;
|
||||
vgmstream->loop_start_sample = dsp_nibbles_to_samples(header.loop_start_offset);
|
||||
vgmstream->loop_end_sample = dsp_nibbles_to_samples(header.loop_end_offset)+1;
|
||||
if (vgmstream->loop_end_sample > vgmstream->num_samples) /* don't know why, but it does happen */
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
vgmstream->meta_type = meta_DSP_STD;
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
{
|
||||
/* adpcm coeffs/history */
|
||||
for (i = 0; i < 16; i++)
|
||||
vgmstream->ch[0].adpcm_coef[i] = header.coef[i];
|
||||
vgmstream->ch[0].adpcm_history1_16 = header.initial_hist1;
|
||||
vgmstream->ch[0].adpcm_history2_16 = header.initial_hist2;
|
||||
}
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* .dsp - standard multi-channel dsp as generated by DSPADPCM.exe (later revisions) */
|
||||
VGMSTREAM * init_vgmstream_ngc_mdsp_std(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
|
||||
struct dsp_header header;
|
||||
const off_t header_size = 0x60;
|
||||
const size_t header_size = 0x60;
|
||||
off_t start_offset;
|
||||
int i, c, channel_count;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile, filename, sizeof(filename));
|
||||
if (strcasecmp("dsp", filename_extension(filename)) &&
|
||||
strcasecmp("mdsp", filename_extension(filename))) goto fail;
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "dsp,mdsp"))
|
||||
goto fail;
|
||||
|
||||
if (read_dsp_header(&header, 0, streamFile)) goto fail;
|
||||
if (read_dsp_header(&header, 0x00, streamFile))
|
||||
goto fail;
|
||||
|
||||
channel_count = header.channel_count==0 ? 1 : header.channel_count;
|
||||
start_offset = header_size * channel_count;
|
||||
|
||||
/* check initial predictor/scale */
|
||||
if (header.initial_ps != (uint8_t)read_8bit(start_offset, streamFile))
|
||||
goto fail;
|
||||
|
||||
/* check type==0 and gain==0 */
|
||||
goto fail; /* check initial predictor/scale */
|
||||
if (header.format || header.gain)
|
||||
goto fail;
|
||||
goto fail; /* check type==0 and gain==0 */
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
|
||||
vgmstream = allocate_vgmstream(channel_count, header.loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->num_samples = header.sample_count;
|
||||
vgmstream->sample_rate = header.sample_rate;
|
||||
|
||||
vgmstream->loop_start_sample = dsp_nibbles_to_samples(
|
||||
header.loop_start_offset);
|
||||
vgmstream->loop_end_sample = dsp_nibbles_to_samples(
|
||||
header.loop_end_offset) + 1;
|
||||
|
||||
/* don't know why, but it does happen*/
|
||||
if (vgmstream->loop_end_sample > vgmstream->num_samples)
|
||||
vgmstream->num_samples = header.sample_count;
|
||||
vgmstream->loop_start_sample = dsp_nibbles_to_samples(header.loop_start_offset);
|
||||
vgmstream->loop_end_sample = dsp_nibbles_to_samples(header.loop_end_offset) + 1;
|
||||
if (vgmstream->loop_end_sample > vgmstream->num_samples) /* don't know why, but it does happen*/
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
vgmstream->meta_type = meta_DSP_STD;
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = channel_count == 1 ? layout_none : layout_interleave;
|
||||
vgmstream->meta_type = meta_DSP_STD;
|
||||
vgmstream->interleave_block_size = header.block_size * 8;
|
||||
if (vgmstream->interleave_block_size)
|
||||
vgmstream->interleave_last_block_size = (header.nibble_count / 2 % vgmstream->interleave_block_size + 7) / 8 * 8;
|
||||
@ -313,12 +380,9 @@ VGMSTREAM * init_vgmstream_ngc_mdsp_std(STREAMFILE *streamFile) {
|
||||
for (i = 0; i < channel_count; i++) {
|
||||
if (read_dsp_header(&header, header_size * i, streamFile)) goto fail;
|
||||
|
||||
/* coeffs */
|
||||
/* adpcm coeffs/history */
|
||||
for (c = 0; c < 16; c++)
|
||||
vgmstream->ch[i].adpcm_coef[c] = header.coef[c];
|
||||
|
||||
/* initial history */
|
||||
/* always 0 that I've ever seen, but for completeness... */
|
||||
vgmstream->ch[i].adpcm_history1_16 = header.initial_hist1;
|
||||
vgmstream->ch[i].adpcm_history2_16 = header.initial_hist2;
|
||||
}
|
||||
@ -328,8 +392,7 @@ VGMSTREAM * init_vgmstream_ngc_mdsp_std(STREAMFILE *streamFile) {
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
/* clean up anything we may have opened */
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1226,7 +1289,7 @@ fail:
|
||||
}
|
||||
|
||||
#define WSD_MAX_CHANNELS 2
|
||||
/* .wsd - Custom heade + full interleaved dsp [Phantom Brave (Wii)] */
|
||||
/* .wsd - Custom header + full interleaved dsp [Phantom Brave (Wii)] */
|
||||
VGMSTREAM * init_vgmstream_wii_wsd(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset, header_offset;
|
||||
@ -1999,3 +2062,63 @@ fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define MCADPCM_MAX_CHANNELS 2
|
||||
/* .mcadpcm - Custom header + full interleaved dsp [Skyrim (Switch)] */
|
||||
VGMSTREAM * init_vgmstream_dsp_mcadpcm(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset, header_offset;
|
||||
size_t header_spacing, interleave;
|
||||
int channel_count;
|
||||
struct dsp_header ch_header[MCADPCM_MAX_CHANNELS];
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "mcadpcm"))
|
||||
goto fail;
|
||||
VGM_LOG("1\n");
|
||||
if (read_32bitLE(0x08,streamFile) != read_32bitLE(0x10,streamFile)) /* dsp sizes */
|
||||
goto fail;
|
||||
VGM_LOG("2\n");
|
||||
channel_count = read_32bitLE(0x00,streamFile);
|
||||
if (channel_count > MCADPCM_MAX_CHANNELS) goto fail;
|
||||
|
||||
header_offset = read_32bitLE(0x04,streamFile);
|
||||
header_spacing = read_32bitLE(0x08,streamFile); /* technically dsp size but eh */
|
||||
start_offset = header_offset + 0x60;
|
||||
interleave = header_spacing;
|
||||
VGM_LOG("3\n");
|
||||
/* read dsp */
|
||||
if (!dsp_load_header_le(ch_header, channel_count, streamFile,header_offset,header_spacing)) goto fail;
|
||||
VGM_LOG("4\n");
|
||||
if (!check_dsp_format(ch_header, channel_count)) goto fail;
|
||||
VGM_LOG("5\n");
|
||||
if (!check_dsp_samples(ch_header, channel_count)) goto fail;
|
||||
VGM_LOG("6\n");
|
||||
if (!check_dsp_initial_ps(ch_header, channel_count, streamFile,start_offset,interleave)) goto fail;
|
||||
VGM_LOG("7\n");
|
||||
if (!check_dsp_loop_ps(ch_header, channel_count, streamFile,start_offset,interleave)) goto fail;
|
||||
VGM_LOG("8\n");
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,ch_header[0].loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = ch_header[0].sample_rate;
|
||||
vgmstream->num_samples = ch_header[0].sample_count;
|
||||
vgmstream->loop_start_sample = dsp_nibbles_to_samples(ch_header[0].loop_start_offset);
|
||||
vgmstream->loop_end_sample = dsp_nibbles_to_samples(ch_header[0].loop_end_offset)+1;
|
||||
|
||||
vgmstream->meta_type = meta_DSP_MCADPCM;
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = interleave;
|
||||
setup_vgmstream_dsp(vgmstream, ch_header);
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1,101 +1,215 @@
|
||||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* PDT - Custom Generated File (Mario Party) */
|
||||
/* PDT - Hudson's stream container [Adventure Island (GC), Muscle Champion (GC), Mario Party series (GC)] */
|
||||
VGMSTREAM * init_vgmstream_ngc_pdt(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
int loop_flag;
|
||||
int channel_count;
|
||||
int loop_flag, channel_count, sample_rate;
|
||||
size_t entries, nibble_size, loop_start;
|
||||
off_t entries_offset, coefs_offset, header_offset;
|
||||
off_t channel1_offset = 0, channel2_offset = 0, coef_offset = 0;
|
||||
int total_subsongs, target_subsong = streamFile->stream_index;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "pdt"))
|
||||
goto fail;
|
||||
|
||||
if (read_16bitBE(0x00,streamFile) != 0x01) /* version? */
|
||||
goto fail;
|
||||
if (read_32bitBE(0x04,streamFile) != 0x04) /* entry size? */
|
||||
goto fail;
|
||||
if (read_32bitBE(0x08,streamFile) != 0x7d00) /* not-sample rate? */
|
||||
goto fail;
|
||||
if (read_32bitBE(0x0c,streamFile) != 0x02 && /* not-channels? */
|
||||
read_32bitBE(0x0c,streamFile) != 0x04)
|
||||
goto fail;
|
||||
|
||||
//VGM_LOG("1\n");
|
||||
entries = read_16bitBE(0x02,streamFile);
|
||||
entries_offset = read_32bitBE(0x10,streamFile);
|
||||
coefs_offset = read_32bitBE(0x14,streamFile);
|
||||
//headers_offset = read_32bitBE(0x18,streamFile); /* we'll have pointers to those two */
|
||||
//streams_offset = read_32bitBE(0x1c,streamFile);
|
||||
|
||||
/* find subsongs and target header, as entries can be empty/repeated */
|
||||
{
|
||||
/* tables to cache reads as it can be kinda slow with so many loops */
|
||||
uint32_t data_offsets[0x2000];
|
||||
uint32_t entry_offset, data_offset;
|
||||
int i,j;
|
||||
|
||||
if (entries > 0x2000)
|
||||
goto fail;
|
||||
|
||||
total_subsongs = 0;
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
|
||||
header_offset = 0;
|
||||
for (i = 0; i < entries; i++) {
|
||||
int is_unique = 1;
|
||||
|
||||
entry_offset = read_32bitBE(entries_offset + i*0x04,streamFile);
|
||||
if (entry_offset == 0x00)
|
||||
continue;
|
||||
data_offset = read_32bitBE(entry_offset+0x10,streamFile);
|
||||
|
||||
/* check if current entry header was repeated (same file offset, difference in flags only) */
|
||||
for (j = 0; j < total_subsongs; j++) {
|
||||
if (data_offsets[j] == data_offset) {
|
||||
is_unique = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!is_unique)
|
||||
continue;
|
||||
|
||||
data_offsets[total_subsongs] = data_offset;
|
||||
total_subsongs++;
|
||||
|
||||
/* target GET, but keep going to count subsongs */
|
||||
if (!header_offset && target_subsong == total_subsongs) {
|
||||
header_offset = entry_offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//VGM_LOG("header: %lx\n", header_offset);//todo
|
||||
/* parse header */
|
||||
{
|
||||
uint8_t flags;
|
||||
size_t coef1_entry;
|
||||
off_t coef1_offset;
|
||||
|
||||
flags = read_8bit(header_offset+0x00,streamFile);
|
||||
sample_rate = read_32bitBE(header_offset+0x04,streamFile);
|
||||
/* 0x01: unknown + 0x4000 */
|
||||
sample_rate = read_32bitBE(header_offset+0x04,streamFile);
|
||||
nibble_size = read_32bitBE(header_offset+0x08,streamFile);
|
||||
loop_start = read_32bitBE(header_offset+0x0c,streamFile);
|
||||
|
||||
channel1_offset = read_32bitBE(header_offset+0x10,streamFile);
|
||||
coef1_entry = read_16bitBE(header_offset+0x14,streamFile);
|
||||
coef1_offset = coefs_offset + coef1_entry*0x20;
|
||||
|
||||
if (flags & 0x01) {
|
||||
//size_t coef2_entry;
|
||||
//off_t coef2_offset;
|
||||
|
||||
channel2_offset = read_32bitBE(header_offset+0x18,streamFile);
|
||||
/* always after coef1 in practice */
|
||||
//coef2_entry = read_16bitBE(header_offset+0x1c,streamFile);
|
||||
//coef2_offset = coefs_offset + coef2_entry*0x20;
|
||||
//if (coef1_offset + 0x20 != coef2_offset)
|
||||
// goto fail;
|
||||
}
|
||||
|
||||
coef_offset = coef1_offset;
|
||||
loop_flag = (flags & 0x02);
|
||||
channel_count = (flags & 0x01) ? 2 : 1;
|
||||
}
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
//vgmstream->num_samples = dsp_bytes_to_samples(data_size, channel_count);//todo remove
|
||||
vgmstream->num_samples = dsp_nibbles_to_samples(nibble_size);
|
||||
//vgmstream->loop_start_sample = dsp_bytes_to_samples(loop_start, channel_count);//todo remove
|
||||
vgmstream->loop_start_sample = dsp_nibbles_to_samples(loop_start);
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
vgmstream->meta_type = meta_NGC_PDT;
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_none;
|
||||
dsp_read_coefs_be(vgmstream, streamFile, coef_offset, 0x20);
|
||||
|
||||
vgmstream->num_streams = total_subsongs;
|
||||
vgmstream->stream_size = nibble_size / 2 * channel_count;
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,channel1_offset))
|
||||
goto fail;
|
||||
|
||||
/* channels may start at slightly separated offsets */
|
||||
if (channel_count == 2) {
|
||||
vgmstream->ch[1].channel_start_offset =
|
||||
vgmstream->ch[1].offset = channel2_offset;
|
||||
}
|
||||
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* PDT - custom fake header for split (PDTExt) .ptd [Mario Party (GC)] */
|
||||
VGMSTREAM * init_vgmstream_ngc_pdt_split(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int second_channel_start = -1;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("pdt",filename_extension(filename))) goto fail;
|
||||
int loop_flag, channel_count;
|
||||
|
||||
/* check header */
|
||||
if (read_32bitBE(0x00,streamFile) != 0x50445420) /* "PDT " */
|
||||
goto fail;
|
||||
if (read_32bitBE(0x04,streamFile) != 0x44535020) /* "DSP " */
|
||||
goto fail;
|
||||
if (read_32bitBE(0x08,streamFile) != 0x48454144) /* "HEAD " */
|
||||
goto fail;
|
||||
if (read_16bitBE(0x0C,streamFile) != 0x4552) /* "ER " */
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "pdt"))
|
||||
goto fail;
|
||||
|
||||
loop_flag = (read_32bitBE(0x1C,streamFile)!=2);
|
||||
/* 0x10 fake header + chunks of the original header / data pasted together */
|
||||
if (read_32bitBE(0x00,streamFile) != 0x50445420 && /* "PDT " */
|
||||
read_32bitBE(0x04,streamFile) != 0x44535020 && /* "DSP " */
|
||||
read_32bitBE(0x08,streamFile) != 0x48454144 && /* "HEAD " */
|
||||
read_16bitBE(0x0C,streamFile) != 0x4552) /* "ER " */
|
||||
goto fail;
|
||||
|
||||
start_offset = 0x800;
|
||||
channel_count = (uint16_t)(read_16bitLE(0x0E,streamFile));
|
||||
loop_flag = (read_32bitBE(0x1C,streamFile) != 2);
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
start_offset = 0x800;
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = read_32bitBE(0x14,streamFile);
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
|
||||
if (channel_count == 1)
|
||||
{
|
||||
vgmstream->num_samples = read_32bitBE(0x18,streamFile)*14/8/channel_count/2;
|
||||
if (channel_count == 1) {
|
||||
vgmstream->num_samples = read_32bitBE(0x18,streamFile)*14/8/channel_count/2;
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = read_32bitBE(0x1C,streamFile)*14/8/channel_count/2;
|
||||
vgmstream->loop_end_sample = read_32bitBE(0x18,streamFile)*14/8/channel_count/2;
|
||||
}
|
||||
}
|
||||
else if (channel_count == 2)
|
||||
{
|
||||
vgmstream->num_samples = read_32bitBE(0x18,streamFile)*14/8/channel_count;
|
||||
else if (channel_count == 2) {
|
||||
vgmstream->num_samples = read_32bitBE(0x18,streamFile)*14/8/channel_count;
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = read_32bitBE(0x1C,streamFile)*14/8/channel_count;
|
||||
vgmstream->loop_end_sample = read_32bitBE(0x18,streamFile)*14/8/channel_count;
|
||||
}
|
||||
second_channel_start = (get_streamfile_size(streamFile)+start_offset)/2;
|
||||
}
|
||||
else
|
||||
{
|
||||
goto fail;
|
||||
else {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->meta_type = meta_NGC_PDT;
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_none;
|
||||
dsp_read_coefs_be(vgmstream, streamFile, 0x50, 0x20);
|
||||
|
||||
if (vgmstream->coding_type == coding_NGC_DSP) {
|
||||
int i;
|
||||
for (i=0;i<16;i++) {
|
||||
vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x50+i*2,streamFile);
|
||||
}
|
||||
if (vgmstream->channels == 2) {
|
||||
for (i=0;i<16;i++) {
|
||||
vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x70+i*2,streamFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
|
||||
/* 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[0].channel_start_offset=start_offset;
|
||||
if (channel_count == 2) {
|
||||
if (second_channel_start == -1) goto fail;
|
||||
vgmstream->ch[1].channel_start_offset=second_channel_start;
|
||||
}
|
||||
vgmstream->ch[i].offset = vgmstream->ch[i].channel_start_offset;
|
||||
}
|
||||
if (channel_count == 2) {
|
||||
vgmstream->ch[1].channel_start_offset =
|
||||
vgmstream->ch[1].offset = ((get_streamfile_size(streamFile)+start_offset) / channel_count);
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -179,7 +179,7 @@ VGMSTREAM * init_vgmstream_pc_mxst(STREAMFILE *streamFile) {
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->layout_type = layout_mxch_blocked;
|
||||
vgmstream->layout_type = layout_blocked_mxch;
|
||||
|
||||
vgmstream->meta_type = meta_PC_MXST;
|
||||
if(bits_per_sample == 8)
|
||||
@ -207,7 +207,7 @@ VGMSTREAM * init_vgmstream_pc_mxst(STREAMFILE *streamFile) {
|
||||
}
|
||||
|
||||
}
|
||||
mxch_block_update(start_offset, vgmstream);
|
||||
block_update_mxch(start_offset, vgmstream);
|
||||
|
||||
return vgmstream;
|
||||
|
||||
|
76
src/meta/pcm_sre.c
Normal file
76
src/meta/pcm_sre.c
Normal file
@ -0,0 +1,76 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* .PCM+SRE. - Capcom's header+data container thing [Viewtiful Joe (PS2)] */
|
||||
VGMSTREAM * init_vgmstream_pcm_sre(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
STREAMFILE * streamHeader = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag, channel_count;
|
||||
size_t table1_entries, table2_entries;
|
||||
off_t table1_offset, table2_offset, header_offset;
|
||||
int total_subsongs, target_subsong = streamFile->stream_index;
|
||||
|
||||
|
||||
/* checks */
|
||||
/* .pcm=data, .sre=header */
|
||||
if (!check_extensions(streamFile, "pcm"))
|
||||
goto fail;
|
||||
|
||||
/* first PS-ADPCM frame should be is null */
|
||||
if (read_32bitBE(0x00,streamFile) != 0x00020000 ||
|
||||
read_32bitBE(0x04,streamFile) != 0x00000000 ||
|
||||
read_32bitBE(0x08,streamFile) != 0x00000000 ||
|
||||
read_32bitBE(0x0c,streamFile) != 0x00000000)
|
||||
goto fail;
|
||||
|
||||
streamHeader = open_streamfile_by_ext(streamFile, "sre");
|
||||
if (!streamHeader) goto fail;
|
||||
|
||||
table1_entries = read_32bitLE(0x00, streamHeader);
|
||||
table1_offset = read_32bitLE(0x04, streamHeader);
|
||||
table2_entries = read_32bitLE(0x08, streamHeader);
|
||||
table2_offset = read_32bitLE(0x0c, streamHeader);
|
||||
if (table1_entries*0x60 + table1_offset != table2_offset)
|
||||
goto fail; /* just in case */
|
||||
|
||||
total_subsongs = table2_entries;
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||
|
||||
header_offset = table2_offset + (target_subsong-1)*0x20;
|
||||
|
||||
channel_count = read_32bitLE(header_offset+0x00,streamHeader);
|
||||
loop_flag = read_32bitLE(header_offset+0x18,streamHeader);
|
||||
start_offset = read_32bitLE(header_offset+0x08,streamHeader);
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = read_16bitLE(header_offset+0x04,streamHeader);
|
||||
vgmstream->meta_type = meta_PCM_SRE;
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x1000;
|
||||
|
||||
vgmstream->num_samples = ps_bytes_to_samples(read_32bitLE(header_offset+0x0c,streamHeader), channel_count);
|
||||
vgmstream->loop_start_sample = ps_bytes_to_samples(read_32bitLE(header_offset+0x10,streamHeader)*channel_count, channel_count);
|
||||
vgmstream->loop_end_sample = ps_bytes_to_samples(read_32bitLE(header_offset+0x14,streamHeader)*channel_count, channel_count);
|
||||
|
||||
vgmstream->num_streams = total_subsongs;
|
||||
vgmstream->stream_size = read_32bitLE(header_offset+0x0c,streamHeader);
|
||||
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
|
||||
close_streamfile(streamHeader);
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_streamfile(streamHeader);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
@ -74,7 +74,7 @@ static int get_adm_loop_info(STREAMFILE *streamFile, off_t *loop_start_offset) {
|
||||
int i, name_index = -1, loop_flag;
|
||||
off_t offset;
|
||||
|
||||
streamExe = open_stream_name(streamFile, "SLPM_655.55");
|
||||
streamExe = open_streamfile_by_filename(streamFile, "SLPM_655.55");
|
||||
if (!streamExe) goto fail;
|
||||
|
||||
get_streamfile_filename(streamFile, file_name, PATH_LIMIT);
|
||||
|
@ -1,92 +1,116 @@
|
||||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
static STREAMFILE* setup_bmdx_streamfile(STREAMFILE *streamFile, off_t start_offset, size_t data_size);
|
||||
|
||||
|
||||
/* .bmdx - from Beatmania IIDX (PS2) games */
|
||||
VGMSTREAM * init_vgmstream_ps2_bmdx(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
int loop_flag=0;
|
||||
int channel_count;
|
||||
STREAMFILE *temp_streamFile = NULL;
|
||||
off_t start_offset;
|
||||
int i;
|
||||
size_t data_size;
|
||||
int loop_flag, channel_count, encryption;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("bmdx",filename_extension(filename))) goto fail;
|
||||
|
||||
/* check NPSF Header */
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "bmdx"))
|
||||
goto fail;
|
||||
if (read_32bitBE(0x00,streamFile) != 0x01006408 ||
|
||||
read_32bitBE(0x04,streamFile) != 0)
|
||||
read_32bitBE(0x04,streamFile) != 0x00)
|
||||
goto fail;
|
||||
|
||||
/* check loop */
|
||||
loop_flag = (read_32bitLE(0x10,streamFile)!=0);
|
||||
channel_count=read_32bitLE(0x1C,streamFile);
|
||||
|
||||
start_offset = read_32bitLE(0x08,streamFile);
|
||||
data_size = read_32bitLE(0x0c,streamFile);
|
||||
loop_flag = (read_32bitLE(0x10,streamFile) != 0x00);
|
||||
channel_count = read_32bitLE(0x1C,streamFile);
|
||||
encryption = (read_32bitLE(0x20,streamFile) == 1);
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = read_32bitLE(0x18,streamFile);
|
||||
|
||||
/* Check for Compression Scheme */
|
||||
if (read_32bitLE(0x20,streamFile) == 1)
|
||||
vgmstream->coding_type = coding_PSX_bmdx;
|
||||
else
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->num_samples = read_32bitLE(0x0c,streamFile)*28/16/channel_count;
|
||||
|
||||
/* Get loop point values */
|
||||
if(vgmstream->loop_flag) {
|
||||
vgmstream->loop_start_sample = read_32bitLE(0x10,streamFile)*28/16/channel_count;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
}
|
||||
|
||||
if (channel_count == 1) {
|
||||
vgmstream->layout_type = layout_none;
|
||||
} else if (channel_count > 1) {
|
||||
vgmstream->interleave_block_size = read_32bitLE(0x24,streamFile);
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
}
|
||||
vgmstream->num_samples = ps_bytes_to_samples(data_size, channel_count);
|
||||
vgmstream->loop_start_sample = ps_bytes_to_samples(read_32bitLE(0x10,streamFile), channel_count);
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
vgmstream->meta_type = meta_PS2_BMDX;
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = (channel_count == 1) ? layout_none : layout_interleave;
|
||||
vgmstream->interleave_block_size = read_32bitLE(0x24,streamFile);
|
||||
|
||||
start_offset = read_32bitLE(0x08,streamFile);
|
||||
|
||||
if (vgmstream->coding_type == coding_PSX_bmdx)
|
||||
{
|
||||
uint8_t xor = read_8bit(start_offset,streamFile);
|
||||
uint8_t add = (~(uint8_t)read_8bit(start_offset+2,streamFile))+1;
|
||||
int c;
|
||||
for (c=0;c<channel_count;c++) {
|
||||
vgmstream->ch[c].bmdx_xor = xor;
|
||||
vgmstream->ch[c].bmdx_add = add;
|
||||
}
|
||||
/* later games are encrypted [beatmaniaIIDX 14 GOLD (PS2)] */
|
||||
if (encryption) {
|
||||
temp_streamFile = setup_bmdx_streamfile(streamFile, start_offset, data_size);
|
||||
if (!temp_streamFile) goto fail;
|
||||
}
|
||||
|
||||
/* open the file for reading by each channel */
|
||||
{
|
||||
for (i=0;i<channel_count;i++) {
|
||||
if (!vgmstream->ch[0].streamfile) {
|
||||
vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,0x8000);
|
||||
}
|
||||
vgmstream->ch[i].streamfile = vgmstream->ch[0].streamfile;
|
||||
if (!vgmstream_open_stream(vgmstream,encryption ? temp_streamFile : streamFile,start_offset))
|
||||
goto fail;
|
||||
|
||||
if (!vgmstream->ch[i].streamfile) goto fail;
|
||||
|
||||
vgmstream->ch[i].channel_start_offset=
|
||||
vgmstream->ch[i].offset=
|
||||
(off_t)(start_offset+vgmstream->interleave_block_size*i);
|
||||
}
|
||||
}
|
||||
|
||||
close_streamfile(temp_streamFile);
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
close_streamfile(temp_streamFile);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint8_t xor;
|
||||
uint8_t add;
|
||||
off_t start_offset;
|
||||
size_t data_size;
|
||||
} bmdx_decryption_data;
|
||||
|
||||
static size_t bmdx_decryption_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, bmdx_decryption_data* data) {
|
||||
size_t bytes_read;
|
||||
int i;
|
||||
|
||||
bytes_read = streamfile->read(streamfile, dest, offset, length);
|
||||
|
||||
/* decrypt data (xor) */
|
||||
for (i = 0; i < bytes_read; i++) {
|
||||
if (offset+i >= data->start_offset && offset+i < data->start_offset + data->data_size) {
|
||||
if (((offset+i) % 0x10) == 0) /* XOR header byte per frame */
|
||||
dest[i] = dest[i] ^ data->xor;
|
||||
else if (((offset+i) % 0x10) == 2) /* ADD first data byte per frame */
|
||||
dest[i] = (uint8_t)(dest[i] + data->add);
|
||||
}
|
||||
}
|
||||
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
static STREAMFILE* setup_bmdx_streamfile(STREAMFILE *streamFile, off_t start_offset, size_t data_size) {
|
||||
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||
bmdx_decryption_data io_data = {0};
|
||||
size_t io_data_size = sizeof(bmdx_decryption_data);
|
||||
|
||||
/* setup decryption (usually xor=0xFF and add=0x02) */
|
||||
io_data.xor = read_8bit(start_offset,streamFile);
|
||||
io_data.add = (~(uint8_t)read_8bit(start_offset+2,streamFile)) + 0x01;
|
||||
io_data.start_offset = start_offset;
|
||||
io_data.data_size = data_size;
|
||||
|
||||
|
||||
/* setup custom streamfile */
|
||||
new_streamFile = open_wrap_streamfile(streamFile);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, bmdx_decryption_read,NULL);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
return temp_streamFile;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ VGMSTREAM * init_vgmstream_filp(STREAMFILE *streamFile) {
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = read_32bitLE(0x110,streamFile);
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_filp_blocked;
|
||||
vgmstream->layout_type = layout_blocked_filp;
|
||||
vgmstream->meta_type = meta_FILP;
|
||||
|
||||
/* open the file for reading */
|
||||
@ -50,7 +50,7 @@ VGMSTREAM * init_vgmstream_filp(STREAMFILE *streamFile) {
|
||||
}
|
||||
}
|
||||
|
||||
filp_block_update(start_offset,vgmstream);
|
||||
block_update_filp(start_offset,vgmstream);
|
||||
vgmstream->num_samples = read_32bitLE(0x10C,streamFile)/16*28;
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = 0;
|
||||
|
@ -36,7 +36,7 @@ VGMSTREAM * init_vgmstream_ps2_iab(STREAMFILE *streamFile) {
|
||||
vgmstream->sample_rate = read_32bitLE(0x4,streamFile);
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
|
||||
vgmstream->layout_type = layout_ps2_iab_blocked;
|
||||
vgmstream->layout_type = layout_blocked_ps2_iab;
|
||||
vgmstream->interleave_block_size = read_32bitLE(0xC, streamFile);
|
||||
vgmstream->meta_type = meta_PS2_IAB;
|
||||
|
||||
@ -50,16 +50,16 @@ VGMSTREAM * init_vgmstream_ps2_iab(STREAMFILE *streamFile) {
|
||||
}
|
||||
|
||||
/* Calc num_samples */
|
||||
ps2_iab_block_update(start_offset, vgmstream);
|
||||
block_update_ps2_iab(start_offset, vgmstream);
|
||||
vgmstream->num_samples=0;
|
||||
|
||||
do
|
||||
{
|
||||
vgmstream->num_samples += 0x4000 * 14 / 16;
|
||||
ps2_iab_block_update(vgmstream->next_block_offset, vgmstream);
|
||||
block_update_ps2_iab(vgmstream->next_block_offset, vgmstream);
|
||||
} while (vgmstream->next_block_offset < get_streamfile_size(streamFile));
|
||||
|
||||
ps2_iab_block_update(start_offset, vgmstream);
|
||||
block_update_ps2_iab(start_offset, vgmstream);
|
||||
|
||||
return vgmstream;
|
||||
|
||||
|
@ -1,63 +1,104 @@
|
||||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* JSTM (.STM (renamed .JSTM) from Tantei Jinguji Saburo - Kind of Blue) */
|
||||
static STREAMFILE* setup_jstm_streamfile(STREAMFILE *streamFile, off_t start_offset);
|
||||
|
||||
/* JSTM - from Tantei Jinguji Saburo - Kind of Blue (PS2) */
|
||||
VGMSTREAM * init_vgmstream_ps2_jstm(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset = 0x20;
|
||||
int loop_flag;
|
||||
int channel_count;
|
||||
char filename[PATH_LIMIT];
|
||||
STREAMFILE *temp_streamFile = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag, channel_count;
|
||||
|
||||
/* check extension */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("stm",filename_extension(filename)) &&
|
||||
strcasecmp("jstm",filename_extension(filename))) goto fail;
|
||||
|
||||
/* check header (JSTM) */
|
||||
if (read_32bitBE(0x0,streamFile) != 0x4A53544D) goto fail;
|
||||
/* checks */
|
||||
/* .stm: original, .jstm: header id */
|
||||
if (!check_extensions(streamFile, "stm,jstm"))
|
||||
goto fail;
|
||||
if (read_32bitBE(0x00,streamFile) != 0x4A53544D) /* "JSTM" */
|
||||
goto fail;
|
||||
|
||||
loop_flag = (read_32bitLE(0x14,streamFile) != 0);
|
||||
channel_count = read_16bitLE(0x4,streamFile);
|
||||
|
||||
// hmm, don't know what 6 is, one is probably bytes per sample and the
|
||||
// other is channels, but who can say?
|
||||
if (channel_count != read_16bitLE(0x6,streamFile)) goto fail;
|
||||
start_offset = 0x20;
|
||||
channel_count = read_16bitLE(0x04,streamFile);
|
||||
if (channel_count != read_16bitLE(0x06,streamFile)) /* 0x02, interleave? */
|
||||
goto fail;
|
||||
loop_flag = (read_32bitLE(0x14,streamFile) != -1);
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the statistics vitale */
|
||||
vgmstream->sample_rate = read_32bitLE(0x8,streamFile);
|
||||
vgmstream->coding_type = coding_PCM16LE_XOR_int;
|
||||
vgmstream->num_samples = read_32bitLE(0xC,streamFile)/2/channel_count;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->sample_rate = read_32bitLE(0x08,streamFile);
|
||||
vgmstream->num_samples = pcm_bytes_to_samples(read_32bitLE(0x0C,streamFile),channel_count,16);
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = pcm_bytes_to_samples(read_32bitLE(0x14,streamFile),channel_count,16);
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
}
|
||||
|
||||
vgmstream->meta_type = meta_PS2_JSTM;
|
||||
vgmstream->coding_type = coding_PCM16LE;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x02;
|
||||
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample=read_32bitLE(0x14,streamFile)/2/channel_count;
|
||||
vgmstream->loop_end_sample=vgmstream->num_samples;
|
||||
}
|
||||
|
||||
/* 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 + 2*i;
|
||||
vgmstream->ch[i].key_xor = 0x5A5A;
|
||||
}
|
||||
}
|
||||
temp_streamFile = setup_jstm_streamfile(streamFile, start_offset);
|
||||
if (!temp_streamFile) goto fail;
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,temp_streamFile,start_offset))
|
||||
goto fail;
|
||||
|
||||
close_streamfile(temp_streamFile);
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
close_streamfile(temp_streamFile);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
off_t start_offset;
|
||||
} jstm_decryption_data;
|
||||
|
||||
static size_t jstm_decryption_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, jstm_decryption_data* data) {
|
||||
size_t bytes_read;
|
||||
int i;
|
||||
|
||||
bytes_read = streamfile->read(streamfile, dest, offset, length);
|
||||
|
||||
/* decrypt data (xor) */
|
||||
for (i = 0; i < bytes_read; i++) {
|
||||
if (offset+i >= data->start_offset) {
|
||||
//VGM_LOG("xor %x to %x\n", dest[i], dest[i] ^ 0x5A);getchar();
|
||||
dest[i] = dest[i] ^ 0x5A;
|
||||
}
|
||||
}
|
||||
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
static STREAMFILE* setup_jstm_streamfile(STREAMFILE *streamFile, off_t start_offset) {
|
||||
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||
jstm_decryption_data io_data = {0};
|
||||
size_t io_data_size = sizeof(jstm_decryption_data);
|
||||
|
||||
/* setup decryption */
|
||||
io_data.start_offset = start_offset;
|
||||
|
||||
|
||||
/* setup custom streamfile */
|
||||
new_streamFile = open_wrap_streamfile(streamFile);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, jstm_decryption_read,NULL);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
return temp_streamFile;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ VGMSTREAM * init_vgmstream_ps2_rxws(STREAMFILE *streamFile) {
|
||||
(read_32bitBE(0x00,streamFile) == 0x444E4257)) /* "DNBW" (BE) */
|
||||
goto fail;
|
||||
|
||||
streamHeader = open_stream_ext(streamFile, "xwh");
|
||||
streamHeader = open_streamfile_by_ext(streamFile, "xwh");
|
||||
if (!streamHeader) goto fail;
|
||||
} else {
|
||||
streamHeader = streamFile;
|
||||
|
@ -46,7 +46,7 @@ VGMSTREAM * init_vgmstream_ps2_strlr(STREAMFILE *streamFile) {
|
||||
vgmstream->sample_rate = 48000;
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
|
||||
vgmstream->layout_type = layout_ps2_strlr_blocked;
|
||||
vgmstream->layout_type = layout_blocked_ps2_strlr;
|
||||
//vgmstream->interleave_block_size = read_32bitLE(0xC, streamFile);
|
||||
vgmstream->meta_type = meta_PS2_STRLR;
|
||||
|
||||
@ -60,16 +60,16 @@ VGMSTREAM * init_vgmstream_ps2_strlr(STREAMFILE *streamFile) {
|
||||
}
|
||||
|
||||
/* Calc num_samples */
|
||||
ps2_strlr_block_update(start_offset, vgmstream);
|
||||
block_update_ps2_strlr(start_offset, vgmstream);
|
||||
vgmstream->num_samples=0;
|
||||
|
||||
do
|
||||
{
|
||||
vgmstream->num_samples += vgmstream->current_block_size * 14 / 16;
|
||||
ps2_strlr_block_update(vgmstream->next_block_offset, vgmstream);
|
||||
block_update_ps2_strlr(vgmstream->next_block_offset, vgmstream);
|
||||
} while (vgmstream->next_block_offset < get_streamfile_size(streamFile));
|
||||
|
||||
ps2_strlr_block_update(start_offset, vgmstream);
|
||||
block_update_ps2_strlr(start_offset, vgmstream);
|
||||
|
||||
return vgmstream;
|
||||
|
||||
|
@ -1,43 +1,46 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* VDS/VDM - from Grafitti Kingdom / Rakugaki Oukoku 2 */
|
||||
/* VDS/VDM - from Procyon Studio games [Grafitti Kingdom / Rakugaki Oukoku 2 (PS2), Tsukiyo ni Saraba (PS2)] */
|
||||
VGMSTREAM * init_vgmstream_ps2_vds_vdm(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag, channel_count;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
|
||||
/* checks */
|
||||
if ( !check_extensions(streamFile,"vds,vdm"))
|
||||
goto fail;
|
||||
|
||||
if (read_32bitBE(0x00,streamFile) != 0x56445320 && /* "VDS " (music)*/
|
||||
read_32bitBE(0x00,streamFile) != 0x56444D20) /* "VDM " (voices) */
|
||||
goto fail;
|
||||
|
||||
loop_flag = read_8bit(0x20,streamFile);
|
||||
channel_count = read_32bitLE(0x10,streamFile);
|
||||
start_offset = 0x800;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = channel_count > 1 ? layout_interleave : layout_none;
|
||||
vgmstream->meta_type = meta_PS2_VDS_VDM;
|
||||
|
||||
start_offset = 0x800;
|
||||
vgmstream->num_samples = read_32bitLE(0x04,streamFile) * 28 / 16 / channel_count;
|
||||
/* 0x08: unknown, always 10 */
|
||||
/* 0x08: unknown, always 0x10 */
|
||||
vgmstream->sample_rate = read_32bitLE(0x0c,streamFile);
|
||||
vgmstream->channels = channel_count; /*0x10*/
|
||||
vgmstream->interleave_block_size = read_32bitLE(0x14,streamFile);
|
||||
vgmstream->loop_start_sample = (read_32bitLE(0x18,streamFile) - start_offset) * 28 / 16 / channel_count;
|
||||
vgmstream->loop_end_sample = (read_32bitLE(0x1c,streamFile) - start_offset) * 28 / 16 / channel_count;
|
||||
vgmstream->loop_flag = loop_flag; /*0x20*/
|
||||
/*0x21: volume? */
|
||||
/*0x22: pan? */
|
||||
/*0x23: 02=VDS 04=VDM? */
|
||||
|
||||
/* open the file for reading */
|
||||
/* when looping (or maybe when stereo) data_size at 0x04 is actually smaller than file_size,
|
||||
* sometimes cutting outros with loop disabled; doesn't affect looping though */
|
||||
if (!loop_flag)
|
||||
vgmstream->num_samples = ps_bytes_to_samples(read_32bitLE(0x04,streamFile), channel_count);
|
||||
else
|
||||
vgmstream->num_samples = ps_bytes_to_samples(get_streamfile_size(streamFile) - start_offset, channel_count);
|
||||
vgmstream->loop_start_sample = ps_bytes_to_samples(read_32bitLE(0x18,streamFile) - start_offset, channel_count);
|
||||
vgmstream->loop_end_sample = ps_bytes_to_samples(read_32bitLE(0x1c,streamFile) - start_offset, channel_count);
|
||||
/* 0x21: volume?, 0x22: pan?, 0x23: 02=VDS 04=VDM? 02/05=VDM in Tsukiyo ni Saraba? */
|
||||
|
||||
vgmstream->meta_type = meta_PS2_VDS_VDM;
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = (channel_count == 1) ? layout_none : layout_interleave;
|
||||
vgmstream->interleave_block_size = read_32bitLE(0x14,streamFile);
|
||||
|
||||
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
@ -1,6 +1,5 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* MSF - Sony's PS3 SDK format (MultiStream File) */
|
||||
VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) {
|
||||
@ -11,10 +10,12 @@ VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) {
|
||||
int loop_flag = 0, channel_count;
|
||||
|
||||
|
||||
/* check extension, case insensitive (.at3: Silent Hill HD Collection, .mp3: Darkstalkers Resurrection) */
|
||||
if (!check_extensions(streamFile,"msf,at3,mp3")) goto fail;
|
||||
/* checks */
|
||||
/* .msf: standard, .at3: Silent Hill HD Collection, .mp3: Darkstalkers Resurrection */
|
||||
if (!check_extensions(streamFile,"msf,at3,mp3"))
|
||||
goto fail;
|
||||
|
||||
/* "WMSF" variation with a mini header over the MSFC header, same extension */
|
||||
/* "WMSF" variation with a mini header over the MSFC header [Dai-2-Ji Super Robot Generations (PS3)] */
|
||||
if (read_32bitBE(0x00,streamFile) == 0x574D5346) {
|
||||
header_offset = 0x10;
|
||||
}
|
||||
@ -35,7 +36,7 @@ VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) {
|
||||
/* byte flags, not in MSFv1 or v2
|
||||
* 0x01/02/04/08: loop marker 0/1/2/3
|
||||
* 0x10: resample options (force 44/48khz)
|
||||
* 0x20: VBR MP3
|
||||
* 0x20: VBR MP3 source (changed into simplified 0x1a1 CBR)
|
||||
* 0x40: joint stereo MP3 (apparently interleaved stereo for other formats)
|
||||
* 0x80+: (none/reserved) */
|
||||
flags = read_32bitBE(header_offset+0x14,streamFile);
|
||||
@ -57,7 +58,7 @@ VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) {
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* Sample rate hack for strange MSFv1 files that don't have a specified frequency */
|
||||
/* sample rate hack for strange MSFv1 files that don't have it */
|
||||
vgmstream->sample_rate = read_32bitBE(header_offset+0x10,streamFile);
|
||||
if (vgmstream->sample_rate == 0x00000000) /* PS ADPCM only? */
|
||||
vgmstream->sample_rate = 48000;
|
||||
@ -65,43 +66,43 @@ VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) {
|
||||
vgmstream->meta_type = meta_PS3_MSF;
|
||||
|
||||
switch (codec_id) {
|
||||
case 0x0: /* PCM (Big Endian) */
|
||||
case 0x1: { /* PCM (Little Endian) */
|
||||
case 0x00: /* PCM (Big Endian) */
|
||||
case 0x01: { /* PCM (Little Endian) [Smash Cars (PS3)] */
|
||||
vgmstream->coding_type = codec_id==0 ? coding_PCM16BE : coding_PCM16LE;
|
||||
vgmstream->layout_type = channel_count == 1 ? layout_none : layout_interleave;
|
||||
vgmstream->interleave_block_size = 2;
|
||||
|
||||
vgmstream->num_samples = data_size/2/channel_count;
|
||||
vgmstream->num_samples = pcm_bytes_to_samples(data_size, channel_count,16);
|
||||
if (loop_flag){
|
||||
vgmstream->loop_start_sample = loop_start/2/channel_count;
|
||||
vgmstream->loop_end_sample = loop_end/2/channel_count;
|
||||
vgmstream->loop_start_sample = pcm_bytes_to_samples(loop_start, channel_count,16);
|
||||
vgmstream->loop_end_sample = pcm_bytes_to_samples(loop_end, channel_count,16);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x2: { /* PCM 32 (Float) */
|
||||
goto fail; //probably unused/spec only
|
||||
case 0x02: { /* PCM 32 (Float) */
|
||||
goto fail; /* probably unused/spec only */
|
||||
}
|
||||
|
||||
case 0x3: { /* PS ADPCM */
|
||||
case 0x03: { /* PS ADPCM [Smash Cars (PS3)] */
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = channel_count == 1 ? layout_none : layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x10;
|
||||
|
||||
vgmstream->num_samples = data_size*28/16/channel_count;
|
||||
vgmstream->num_samples = ps_bytes_to_samples(data_size, channel_count);
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = loop_start*28/16/channel_count;
|
||||
vgmstream->loop_end_sample = loop_end*28/16/channel_count;
|
||||
vgmstream->loop_start_sample = ps_bytes_to_samples(loop_start,channel_count);
|
||||
vgmstream->loop_end_sample = ps_bytes_to_samples(loop_end,channel_count);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
case 0x4: /* ATRAC3 low (66 kbps, frame size 96, Joint Stereo) */
|
||||
case 0x5: /* ATRAC3 mid (105 kbps, frame size 152) */
|
||||
case 0x6: { /* ATRAC3 high (132 kbps, frame size 192) */
|
||||
case 0x04: /* ATRAC3 low (66 kbps, frame size 96, Joint Stereo) [Silent Hill HD (PS3)] */
|
||||
case 0x05: /* ATRAC3 mid (105 kbps, frame size 152) [Atelier Rorona (PS3)] */
|
||||
case 0x06: { /* ATRAC3 high (132 kbps, frame size 192) [Tekken Tag Tournament HD (PS3)] */
|
||||
ffmpeg_codec_data *ffmpeg_data = NULL;
|
||||
uint8_t buf[100];
|
||||
int32_t bytes, block_size, encoder_delay, joint_stereo;
|
||||
@ -141,67 +142,55 @@ VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) {
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
case 0x7: { /* MPEG (LAME MP3 of any quality) */
|
||||
/* delegate to FFMpeg, it can parse MSF files */
|
||||
ffmpeg_codec_data *ffmpeg_data = init_ffmpeg_offset(streamFile, header_offset, streamFile->get_size(streamFile) );
|
||||
#if defined(VGM_USE_FFMPEG) && !defined(VGM_USE_MPEG)
|
||||
case 0x07: { /* MPEG (CBR LAME MP3) [Dengeki Bunko Fighting Climax (PS3)] */
|
||||
ffmpeg_codec_data *ffmpeg_data = NULL;
|
||||
|
||||
ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset, streamFile->get_size(streamFile) );
|
||||
if ( !ffmpeg_data ) goto fail;
|
||||
vgmstream->codec_data = ffmpeg_data;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
/* vgmstream->num_samples = ffmpeg_data->totalSamples; */ /* duration may not be set/inaccurate */
|
||||
vgmstream->num_samples = (int64_t)data_size * ffmpeg_data->sampleRate * 8 / ffmpeg_data->bitrate;
|
||||
if (loop_flag) {
|
||||
//todo properly apply encoder delay, which seems to vary between 1152 (1f), 528, 576 or 528+576
|
||||
int frame_size = ffmpeg_data->frameSize;
|
||||
vgmstream->loop_start_sample = (int64_t)loop_start * ffmpeg_data->sampleRate * 8 / ffmpeg_data->bitrate;
|
||||
vgmstream->loop_start_sample -= vgmstream->loop_start_sample==frame_size ? frame_size
|
||||
: vgmstream->loop_start_sample % frame_size;
|
||||
vgmstream->loop_end_sample = (int64_t)loop_end * ffmpeg_data->sampleRate * 8 / ffmpeg_data->bitrate;
|
||||
vgmstream->loop_end_sample -= vgmstream->loop_end_sample==frame_size ? frame_size
|
||||
: vgmstream->loop_end_sample % frame_size;
|
||||
/* loops are always CBR frame beginnings */
|
||||
}
|
||||
|
||||
/* encoder delay varies between 1152 (1f), 528, 576, etc; probably not actually skipped */
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#if defined(VGM_USE_MPEG) && !defined(VGM_USE_FFMPEG)
|
||||
case 0x7: { /* MPEG (LAME MP3 of any quality) */
|
||||
int frame_size = 576; /* todo incorrect looping calcs */
|
||||
|
||||
#ifdef VGM_USE_MPEG
|
||||
case 0x07: { /* MPEG (CBR LAME MP3) []Dengeki Bunko Fighting Climax (PS3) */
|
||||
mpeg_codec_data *mpeg_data = NULL;
|
||||
coding_t ct;
|
||||
|
||||
mpeg_data = init_mpeg(streamFile, start_offset, &ct, vgmstream->channels);
|
||||
mpeg_data = init_mpeg(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels);
|
||||
if (!mpeg_data) goto fail;
|
||||
vgmstream->codec_data = mpeg_data;
|
||||
|
||||
vgmstream->coding_type = ct;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
vgmstream->num_samples = mpeg_bytes_to_samples(data_size, mpeg_data);
|
||||
vgmstream->num_samples -= vgmstream->num_samples % frame_size;
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = mpeg_bytes_to_samples(loop_start, mpeg_data);
|
||||
vgmstream->loop_start_sample -= vgmstream->loop_start_sample % frame_size;
|
||||
vgmstream->loop_end_sample = mpeg_bytes_to_samples(loop_end, mpeg_data);
|
||||
vgmstream->loop_end_sample -= vgmstream->loop_end_sample % frame_size;
|
||||
/* loops are always CBR frame beginnings */
|
||||
}
|
||||
vgmstream->interleave_block_size = 0;
|
||||
|
||||
/* encoder delay varies between 1152 (1f), 528, 576, etc; probably not actually skipped */
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
default: /* 8+: not defined */
|
||||
default: /* 0x08+: not defined */
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
/* open the file for reading */
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
|
@ -105,7 +105,7 @@ VGMSTREAM * init_vgmstream_cdxa(STREAMFILE *streamFile) {
|
||||
vgmstream->xa_channel = xa_channel;
|
||||
|
||||
vgmstream->coding_type = coding_XA;
|
||||
vgmstream->layout_type = layout_xa_blocked;
|
||||
vgmstream->layout_type = layout_blocked_xa;
|
||||
vgmstream->meta_type = meta_PSX_XA;
|
||||
|
||||
if (is_blocked)
|
||||
@ -115,7 +115,7 @@ VGMSTREAM * init_vgmstream_cdxa(STREAMFILE *streamFile) {
|
||||
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
|
||||
goto fail;
|
||||
|
||||
xa_block_update(start_offset,vgmstream);
|
||||
block_update_xa(start_offset,vgmstream);
|
||||
|
||||
return vgmstream;
|
||||
|
||||
|
@ -106,15 +106,22 @@ static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk
|
||||
fmt->codec = (uint16_t)read_16bit(current_chunk+0x8,streamFile);
|
||||
|
||||
switch (fmt->codec) {
|
||||
case 0x00: /* Yamaha ADPCM (raw) [Headhunter (DC), Bomber hehhe (DC)] (unofficial) */
|
||||
if (fmt->bps != 4) goto fail;
|
||||
if (fmt->block_size != 0x02*fmt->channel_count) goto fail;
|
||||
fmt->coding_type = coding_AICA_int;
|
||||
fmt->interleave = 0x01;
|
||||
break;
|
||||
|
||||
case 0x01: /* PCM */
|
||||
switch (fmt->bps) {
|
||||
case 16:
|
||||
fmt->coding_type = big_endian ? coding_PCM16BE : coding_PCM16LE;
|
||||
fmt->interleave = 2;
|
||||
fmt->interleave = 0x02;
|
||||
break;
|
||||
case 8:
|
||||
fmt->coding_type = coding_PCM8_U_int;
|
||||
fmt->interleave = 1;
|
||||
fmt->interleave = 0x01;
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
@ -131,12 +138,17 @@ static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk
|
||||
fmt->coding_type = coding_MS_IMA;
|
||||
break;
|
||||
|
||||
case 0x20: /* Yamaha ADPCM (raw) [Takuyo/Dynamix/etc DC games] */
|
||||
if (fmt->bps != 4) goto fail;
|
||||
fmt->coding_type = coding_AICA;
|
||||
break;
|
||||
|
||||
case 0x69: /* XBOX IMA ADPCM [Dynasty Warriors 5 (Xbox), Rayman Raving Rabbids 2 (PC) --maybe waa/wac/wam/wad?] */
|
||||
if (fmt->bps != 4) goto fail;
|
||||
fmt->coding_type = coding_XBOX_IMA;
|
||||
break;
|
||||
|
||||
case 0x007A: /* MS IMA ADPCM [LA Rush (PC), Psi Ops (PC)] */
|
||||
case 0x007A: /* MS IMA ADPCM [LA Rush (PC), Psi Ops (PC)] (unofficial) */
|
||||
/* 0x007A is apparently "Voxware SC3" but in .MED it's just MS-IMA (0x11) */
|
||||
if (!check_extensions(streamFile,"med"))
|
||||
goto fail;
|
||||
@ -149,13 +161,13 @@ static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk
|
||||
goto fail;
|
||||
break;
|
||||
|
||||
case 0x0555: /* Level-5 0x555 ADPCM */
|
||||
case 0x0555: /* Level-5 0x555 ADPCM (unofficial) */
|
||||
if (!mwv) goto fail;
|
||||
fmt->coding_type = coding_L5_555;
|
||||
fmt->interleave = 0x12;
|
||||
break;
|
||||
|
||||
case 0x5050: /* Ubisoft LyN engine's DSP */
|
||||
case 0x5050: /* Ubisoft LyN engine's DSP (unofficial) */
|
||||
if (!sns) goto fail;
|
||||
fmt->coding_type = coding_NGC_DSP;
|
||||
fmt->interleave = 0x08;
|
||||
@ -249,8 +261,9 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
||||
/* check extension */
|
||||
/* .lwav: to avoid hijacking .wav, .xwav: fake for Xbox games (unneded anymore) */
|
||||
/* .da: The Great Battle VI (PS), .cd: Exector (PS), .med: Psi Ops (PC), .snd: Layton Brothers (iOS/Android),
|
||||
* .adx: Remember11 (PC) sfx */
|
||||
if ( check_extensions(streamFile, "wav,lwav,xwav,da,cd,med,snd,adx") ) {
|
||||
* .adx: Remember11 (PC) sfx
|
||||
* .adp: Headhunter (DC) */
|
||||
if ( check_extensions(streamFile, "wav,lwav,xwav,da,cd,med,snd,adx,adp") ) {
|
||||
;
|
||||
}
|
||||
else if ( check_extensions(streamFile, "mwv") ) {
|
||||
@ -286,6 +299,10 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
||||
/* some Xbox games do this [Dynasty Warriors 3 (Xbox), BloodRayne (Xbox)] */
|
||||
if (riff_size == file_size && read_16bitLE(0x14,streamFile)==0x0069)
|
||||
riff_size -= 0x08;
|
||||
/* some Dreamcast/Naomi games do this [Headhunter (DC), Bomber hehhe (DC)] */
|
||||
if (riff_size + 0x04 == file_size && read_16bitLE(0x14,streamFile)==0x0000)
|
||||
riff_size -= 0x04;
|
||||
|
||||
|
||||
/* check for truncated RIFF */
|
||||
if (file_size < riff_size+0x08) goto fail;
|
||||
@ -315,6 +332,10 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
||||
sns,
|
||||
mwv))
|
||||
goto fail;
|
||||
|
||||
/* some Dreamcast/Naomi games again [Headhunter (DC), Bomber hehhe (DC)] */
|
||||
if (fmt.codec == 0x0000 && chunk_size == 0x12)
|
||||
chunk_size += 0x02;
|
||||
break;
|
||||
|
||||
case 0x64617461: /* "data" */
|
||||
@ -483,6 +504,11 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
||||
vgmstream->num_samples = fact_sample_count;
|
||||
break;
|
||||
|
||||
case coding_AICA:
|
||||
case coding_AICA_int:
|
||||
vgmstream->num_samples = aica_bytes_to_samples(data_size, fmt.channel_count);
|
||||
break;
|
||||
|
||||
case coding_XBOX_IMA:
|
||||
vgmstream->num_samples = xbox_ima_bytes_to_samples(data_size, fmt.channel_count);
|
||||
if (fact_sample_count && fact_sample_count < vgmstream->num_samples)
|
||||
@ -577,6 +603,7 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
||||
switch (fmt.coding_type) {
|
||||
case coding_MSADPCM:
|
||||
case coding_MS_IMA:
|
||||
case coding_AICA:
|
||||
case coding_XBOX_IMA:
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
case coding_FFmpeg:
|
||||
@ -849,7 +876,7 @@ static VGMSTREAM *parse_riff_ogg(STREAMFILE * streamFile, off_t start_offset, si
|
||||
|
||||
io_data.patch_offset = patch_offset;
|
||||
|
||||
custom_streamFile = open_io_streamfile(open_wrap_streamfile(streamFile), &io_data,io_data_size, riff_ogg_io_read);
|
||||
custom_streamFile = open_io_streamfile(open_wrap_streamfile(streamFile), &io_data,io_data_size, riff_ogg_io_read,NULL);
|
||||
if (!custom_streamFile) return NULL;
|
||||
|
||||
vgmstream = init_vgmstream_ogg_vorbis_callbacks(custom_streamFile, NULL, start_offset, &ovmi);
|
||||
|
@ -1179,7 +1179,7 @@ VGMSTREAM * init_vgmstream_rsd6wma(STREAMFILE *streamFile) {
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_RSD6WMA;
|
||||
//vgmstream->num_samples = read_32bitLE(start_offset + 0x00, streamFile); /* ? */
|
||||
//vgmstream->num_samples = read_32bitLE(start_offset + 0x00, streamFile) / channel_count / 2; /* may be PCM data size, but not exact */
|
||||
vgmstream->sample_rate = read_32bitLE(start_offset + 0x04, streamFile);
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
@ -1193,12 +1193,11 @@ VGMSTREAM * init_vgmstream_rsd6wma(STREAMFILE *streamFile) {
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
vgmstream->num_samples = (int32_t)ffmpeg_data->totalSamples; /* probably an estimation */
|
||||
|
||||
vgmstream->num_samples = (int32_t)ffmpeg_data->totalSamples; /* an estimation, sometimes cuts files a bit early */
|
||||
}
|
||||
#else
|
||||
goto fail;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, streamFile, start_offset))
|
||||
goto fail;
|
||||
|
@ -109,7 +109,7 @@ static void get_stream_name(char * stream_name, STREAMFILE *streamFile, int targ
|
||||
size_t name_size = 0;
|
||||
off_t name_offset = 0x10;
|
||||
|
||||
streamInfo = open_stream_ext(streamFile, "sob");
|
||||
streamInfo = open_streamfile_by_ext(streamFile, "sob");
|
||||
if (!streamInfo) goto end;
|
||||
if (read_32bitBE(0x00,streamInfo) != 0x43544632) /* "CTF2" */
|
||||
goto end;
|
||||
|
@ -24,7 +24,7 @@ VGMSTREAM * init_vgmstream_sgxd(STREAMFILE *streamFile) {
|
||||
|
||||
/* SGB+SGH: use SGH as header; otherwise use the current file as header */
|
||||
if (is_sgb) {
|
||||
streamHeader = open_stream_ext(streamFile, "sgh");
|
||||
streamHeader = open_streamfile_by_ext(streamFile, "sgh");
|
||||
if (!streamHeader) goto fail;
|
||||
} else {
|
||||
streamHeader = streamFile;
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "sqex_scd_streamfile.h"
|
||||
|
||||
|
||||
@ -11,7 +12,6 @@ static void scd_ogg_v3_decryption_callback(void *ptr, size_t size, size_t nmemb,
|
||||
/* SCD - Square-Enix games (FF XIII, XIV) */
|
||||
VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
off_t start_offset, tables_offset, meta_offset, extradata_offset, name_offset = 0;
|
||||
int32_t stream_size, extradata_size, loop_start, loop_end;
|
||||
|
||||
@ -26,7 +26,6 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
||||
/* check extension, case insensitive */
|
||||
if ( !check_extensions(streamFile, "scd") )
|
||||
goto fail;
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
|
||||
/** main header **/
|
||||
if (read_32bitBE(0x00,streamFile) != 0x53454442 && /* "SEDB" */
|
||||
@ -281,61 +280,54 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
||||
|
||||
case 0x0A: /* DSP ADPCM [Dragon Quest X (Wii)] */
|
||||
case 0x15: { /* DSP ADPCM [Dragon Quest X (Wii U)] (no apparent differences except higher sample rate) */
|
||||
STREAMFILE * file;
|
||||
int i;
|
||||
const off_t interleave_size = 0x800;
|
||||
const off_t stride_size = interleave_size * channel_count;
|
||||
int i;
|
||||
size_t total_size;
|
||||
scd_int_codec_data * data = NULL;
|
||||
|
||||
layered_layout_data * data = NULL;
|
||||
|
||||
/* interleaved DSPs including the header (so the first 0x800 is 0x60 header + 0x740 data)
|
||||
* so interleave layout can't used; we'll setup de-interleaving streamfiles as layers/channels instead */
|
||||
//todo this could be simplified using a block layout or adding interleave_first_block
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_scd_int;
|
||||
vgmstream->layout_type = layout_layered;
|
||||
|
||||
/* a normal DSP header... */
|
||||
total_size = (read_32bitBE(start_offset+0x04,streamFile)+1)/2;
|
||||
vgmstream->num_samples = read_32bitBE(start_offset+0x00,streamFile);
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = loop_start;
|
||||
vgmstream->loop_end_sample = loop_end+1;
|
||||
}
|
||||
/* read from the first DSP header and verify other channel headers */
|
||||
{
|
||||
total_size = (read_32bitBE(start_offset+0x04,streamFile)+1)/2; /* rounded nibbles / 2 */
|
||||
vgmstream->num_samples = read_32bitBE(start_offset+0x00,streamFile);
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = loop_start;
|
||||
vgmstream->loop_end_sample = loop_end+1;
|
||||
}
|
||||
|
||||
/* verify other channel headers */
|
||||
for (i = 1; i < channel_count; i++) {
|
||||
if (read_32bitBE(start_offset+interleave_size*i+0,streamFile) != vgmstream->num_samples ||
|
||||
(read_32bitBE(start_offset+4,streamFile)+1)/2 != total_size) {
|
||||
goto fail;
|
||||
for (i = 1; i < channel_count; i++) {
|
||||
if ((read_32bitBE(start_offset+4,streamFile)+1)/2 != total_size ||
|
||||
read_32bitBE(start_offset+interleave_size*i+0x00,streamFile) != vgmstream->num_samples) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* the primary streamfile we'll be using */
|
||||
file = streamFile->open(streamFile,filename,stride_size);
|
||||
if (!file) goto fail;
|
||||
/* init layout */
|
||||
data = init_layout_layered(channel_count);
|
||||
if (!data) goto fail;
|
||||
vgmstream->layout_data = data;
|
||||
|
||||
vgmstream->ch[0].streamfile = file;
|
||||
/* open each layer subfile */
|
||||
for (i = 0; i < channel_count; i++) {
|
||||
STREAMFILE* temp_streamFile = setup_scd_dsp_streamfile(streamFile, start_offset+interleave_size*i, interleave_size, stride_size, total_size);
|
||||
if (!temp_streamFile) goto fail;
|
||||
|
||||
data = malloc(sizeof(scd_int_codec_data));
|
||||
data->substream_count = channel_count;
|
||||
data->substreams = calloc(channel_count, sizeof(VGMSTREAM *));
|
||||
data->intfiles = calloc(channel_count, sizeof(STREAMFILE *));
|
||||
|
||||
vgmstream->codec_data = data;
|
||||
|
||||
for (i=0;i<channel_count;i++) {
|
||||
STREAMFILE * intfile =
|
||||
open_scdint_with_STREAMFILE(file, "ARBITRARY.DSP", start_offset+interleave_size*i, interleave_size, stride_size, total_size);
|
||||
if (!intfile) goto fail;
|
||||
|
||||
data->substreams[i] = init_vgmstream_ngc_dsp_std(intfile);
|
||||
data->intfiles[i] = intfile;
|
||||
if (!data->substreams[i]) goto fail;
|
||||
|
||||
/* TODO: only handles mono substreams, though that's all we have with DSP */
|
||||
/* save start things so we can restart for seeking/looping */
|
||||
memcpy(data->substreams[i]->start_ch,data->substreams[i]->ch,sizeof(VGMSTREAMCHANNEL)*1);
|
||||
memcpy(data->substreams[i]->start_vgmstream,data->substreams[i],sizeof(VGMSTREAM));
|
||||
data->layers[i] = init_vgmstream_ngc_dsp_std(temp_streamFile);
|
||||
close_streamfile(temp_streamFile);
|
||||
if (!data->layers[i]) goto fail;
|
||||
}
|
||||
|
||||
/* setup layered VGMSTREAMs */
|
||||
if (!setup_layout_layered(data))
|
||||
goto fail;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -2,72 +2,30 @@
|
||||
#define _SQEX_SCD_STREAMFILE_H_
|
||||
#include "../streamfile.h"
|
||||
|
||||
/* special streamfile type to handle deinterleaving of complete files (based heavily on AIXSTREAMFILE */
|
||||
|
||||
typedef struct _SCDINTSTREAMFILE {
|
||||
STREAMFILE sf;
|
||||
STREAMFILE *real_file;
|
||||
const char * filename;
|
||||
off_t start_physical_offset;
|
||||
off_t current_logical_offset;
|
||||
off_t interleave_block_size;
|
||||
off_t stride_size;
|
||||
size_t total_size;
|
||||
} SCDINTSTREAMFILE;
|
||||
typedef struct {
|
||||
off_t start_physical_offset; /* interleaved data start, for this substream */
|
||||
size_t interleave_block_size; /* max size that can be read before encountering other substreams */
|
||||
size_t stride_size; /* step size between interleave blocks (interleave*channels) */
|
||||
size_t total_size; /* final size of the deinterleaved substream */
|
||||
} scd_dsp_io_data;
|
||||
|
||||
|
||||
/*static*/ STREAMFILE *open_scdint_with_STREAMFILE(STREAMFILE *file, const char * filename, off_t start_offset, off_t interleave_block_size, off_t stride_size, size_t total_size);
|
||||
|
||||
|
||||
static STREAMFILE *open_scdint_impl(SCDINTSTREAMFILE *streamfile,const char * const filename,size_t buffersize) {
|
||||
SCDINTSTREAMFILE *newfile;
|
||||
|
||||
if (strcmp(filename, streamfile->filename))
|
||||
return NULL;
|
||||
|
||||
newfile = malloc(sizeof(SCDINTSTREAMFILE));
|
||||
if (!newfile)
|
||||
return NULL;
|
||||
|
||||
memcpy(newfile,streamfile,sizeof(SCDINTSTREAMFILE));
|
||||
return &newfile->sf;
|
||||
}
|
||||
|
||||
static void close_scdint(SCDINTSTREAMFILE *streamfile) {
|
||||
free(streamfile);
|
||||
return;
|
||||
}
|
||||
|
||||
static size_t get_size_scdint(SCDINTSTREAMFILE *streamfile) {
|
||||
return streamfile->total_size;
|
||||
}
|
||||
|
||||
static size_t get_offset_scdint(SCDINTSTREAMFILE *streamfile) {
|
||||
return streamfile->current_logical_offset;
|
||||
}
|
||||
|
||||
static void get_name_scdint(SCDINTSTREAMFILE *streamfile, char *buffer, size_t length) {
|
||||
strncpy(buffer,streamfile->filename,length);
|
||||
buffer[length-1]='\0';
|
||||
}
|
||||
|
||||
static size_t read_scdint(SCDINTSTREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length) {
|
||||
size_t sz = 0;
|
||||
/* Handles deinterleaving of complete files, skipping portions or other substreams. */
|
||||
static size_t scd_dsp_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, scd_dsp_io_data* data) {
|
||||
size_t total_read = 0;
|
||||
|
||||
while (length > 0) {
|
||||
off_t to_read;
|
||||
off_t length_available;
|
||||
size_t to_read;
|
||||
size_t length_available;
|
||||
off_t block_num;
|
||||
off_t intrablock_offset;
|
||||
off_t physical_offset;
|
||||
|
||||
|
||||
block_num = offset / streamfile->interleave_block_size;
|
||||
intrablock_offset = offset % streamfile->interleave_block_size;
|
||||
streamfile->current_logical_offset = offset;
|
||||
physical_offset = streamfile->start_physical_offset + block_num * streamfile->stride_size + intrablock_offset;
|
||||
|
||||
length_available = streamfile->interleave_block_size - intrablock_offset;
|
||||
block_num = offset / data->interleave_block_size;
|
||||
intrablock_offset = offset % data->interleave_block_size;
|
||||
physical_offset = data->start_physical_offset + block_num*data->stride_size + intrablock_offset;
|
||||
length_available = data->interleave_block_size - intrablock_offset;
|
||||
|
||||
if (length < length_available) {
|
||||
to_read = length;
|
||||
@ -79,16 +37,11 @@ static size_t read_scdint(SCDINTSTREAMFILE *streamfile, uint8_t *dest, off_t off
|
||||
if (to_read > 0) {
|
||||
size_t bytes_read;
|
||||
|
||||
bytes_read = read_streamfile(dest,
|
||||
physical_offset,
|
||||
to_read, streamfile->real_file);
|
||||
|
||||
sz += bytes_read;
|
||||
|
||||
streamfile->current_logical_offset = offset + bytes_read;
|
||||
bytes_read = read_streamfile(dest, physical_offset, to_read, streamfile);
|
||||
total_read += bytes_read;
|
||||
|
||||
if (bytes_read != to_read) {
|
||||
return sz; /* an error which we will not attempt to handle here */
|
||||
return total_read;
|
||||
}
|
||||
|
||||
dest += bytes_read;
|
||||
@ -97,38 +50,43 @@ static size_t read_scdint(SCDINTSTREAMFILE *streamfile, uint8_t *dest, off_t off
|
||||
}
|
||||
}
|
||||
|
||||
return sz;
|
||||
return total_read;
|
||||
}
|
||||
|
||||
/* start_offset is for *this* interleaved stream */
|
||||
/*static*/ STREAMFILE *open_scdint_with_STREAMFILE(STREAMFILE *file, const char * filename, off_t start_offset, off_t interleave_block_size, off_t stride_size, size_t total_size) {
|
||||
SCDINTSTREAMFILE * scd = NULL;
|
||||
static size_t scd_dsp_io_size(STREAMFILE *streamfile, scd_dsp_io_data* data) {
|
||||
return data->total_size;
|
||||
}
|
||||
|
||||
/* _scdint funcs can't handle this case */
|
||||
if (start_offset + total_size > file->get_size(file))
|
||||
return NULL;
|
||||
|
||||
scd = malloc(sizeof(SCDINTSTREAMFILE));
|
||||
if (!scd)
|
||||
return NULL;
|
||||
static STREAMFILE* setup_scd_dsp_streamfile(STREAMFILE *streamFile, off_t start_offset, size_t interleave_block_size, size_t stride_size, size_t total_size) {
|
||||
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||
scd_dsp_io_data io_data = {0};
|
||||
size_t io_data_size = sizeof(scd_dsp_io_data);
|
||||
|
||||
scd->sf.read = (void*)read_scdint;
|
||||
scd->sf.get_size = (void*)get_size_scdint;
|
||||
scd->sf.get_offset = (void*)get_offset_scdint;
|
||||
scd->sf.get_name = (void*)get_name_scdint;
|
||||
scd->sf.get_realname = (void*)get_name_scdint;
|
||||
scd->sf.open = (void*)open_scdint_impl;
|
||||
scd->sf.close = (void*)close_scdint;
|
||||
io_data.start_physical_offset = start_offset;
|
||||
io_data.interleave_block_size = interleave_block_size;
|
||||
io_data.stride_size = stride_size;
|
||||
io_data.total_size = total_size;
|
||||
|
||||
scd->real_file = file;
|
||||
scd->filename = filename;
|
||||
scd->start_physical_offset = start_offset;
|
||||
scd->current_logical_offset = 0;
|
||||
scd->interleave_block_size = interleave_block_size;
|
||||
scd->stride_size = stride_size;
|
||||
scd->total_size = total_size;
|
||||
|
||||
return &scd->sf;
|
||||
/* setup subfile */
|
||||
new_streamFile = open_wrap_streamfile(streamFile);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, scd_dsp_io_read,scd_dsp_io_size);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_fakename_streamfile(temp_streamFile, NULL,"dsp");
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
return temp_streamFile;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* _SCD_STREAMFILE_H_ */
|
||||
|
@ -365,7 +365,7 @@ static STREAMFILE* setup_sead_hca_streamfile(STREAMFILE *streamFile, off_t subfi
|
||||
io_data.header_size = header_size;
|
||||
io_data.key_start = key_start;
|
||||
|
||||
new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, sead_decryption_read);
|
||||
new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, sead_decryption_read,NULL);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
}
|
||||
|
69
src/meta/sthd.c
Normal file
69
src/meta/sthd.c
Normal file
@ -0,0 +1,69 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../layout/layout.h"
|
||||
|
||||
/* STHD - Dream Factory .stx [Kakuto Chojin (Xbox)] */
|
||||
VGMSTREAM * init_vgmstream_sthd(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag, channel_count;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "stx"))
|
||||
goto fail;
|
||||
if (read_32bitBE(0x00,streamFile) != 0x53544844) /* "STHD" */
|
||||
goto fail;
|
||||
/* first block has special values */
|
||||
if (read_32bitLE(0x04,streamFile) != 0x0800 &&
|
||||
read_32bitLE(0x0c,streamFile) != 0x0001 &&
|
||||
read_32bitLE(0x14,streamFile) != 0x0000)
|
||||
goto fail;
|
||||
|
||||
channel_count = read_16bitLE(0x06,streamFile);
|
||||
loop_flag = read_16bitLE(0x18,streamFile) != -1;
|
||||
start_offset = 0x800;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = read_32bitLE(0x20, streamFile); /* repeated ~8 times? */
|
||||
vgmstream->meta_type = meta_STHD;
|
||||
vgmstream->coding_type = coding_XBOX_IMA_int;
|
||||
vgmstream->layout_type = layout_blocked_sthd;
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
|
||||
/* calc num_samples manually (blocks data varies in size) */
|
||||
{
|
||||
/* loop values may change to +1 in first actual block, but this works ok enough */
|
||||
int loop_start_block = (uint16_t)read_16bitLE(0x1a,streamFile);
|
||||
int loop_end_block = (uint16_t)read_16bitLE(0x1c,streamFile);
|
||||
int block_count = 1; /* header block = 0 */
|
||||
|
||||
vgmstream->num_samples = 0;
|
||||
block_update_sthd(start_offset,vgmstream);
|
||||
do {
|
||||
if (block_count == loop_start_block)
|
||||
vgmstream->loop_start_sample = vgmstream->num_samples;
|
||||
if (block_count == loop_end_block)
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
vgmstream->num_samples += xbox_ima_bytes_to_samples(vgmstream->current_block_size, 1);
|
||||
block_update_sthd(vgmstream->next_block_offset,vgmstream);
|
||||
|
||||
block_count++;
|
||||
}
|
||||
while (vgmstream->next_block_offset < get_streamfile_size(streamFile));
|
||||
}
|
||||
|
||||
block_update_sthd(start_offset, vgmstream);
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
@ -122,7 +122,7 @@ VGMSTREAM * init_vgmstream_str_snds(STREAMFILE *streamFile) {
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
vgmstream->layout_type = layout_str_snds_blocked;
|
||||
vgmstream->layout_type = layout_blocked_str_snds;
|
||||
vgmstream->meta_type = meta_STR_SNDS;
|
||||
|
||||
/* channels and loop flag are set by allocate_vgmstream */
|
||||
@ -144,7 +144,7 @@ VGMSTREAM * init_vgmstream_str_snds(STREAMFILE *streamFile) {
|
||||
}
|
||||
|
||||
/* start me up */
|
||||
str_snds_block_update(0,vgmstream);
|
||||
block_update_str_snds(0,vgmstream);
|
||||
|
||||
return vgmstream;
|
||||
|
||||
|
@ -25,7 +25,7 @@ VGMSTREAM * init_vgmstream_sxd(STREAMFILE *streamFile) {
|
||||
if (is_dual) {
|
||||
if (read_32bitBE(0x00,streamFile) != 0x53584453) /* "SXDS" */
|
||||
goto fail;
|
||||
streamHeader = open_stream_ext(streamFile, "sxd1");
|
||||
streamHeader = open_streamfile_by_ext(streamFile, "sxd1");
|
||||
if (!streamHeader) goto fail;
|
||||
} else {
|
||||
streamHeader = streamFile;
|
||||
|
@ -88,10 +88,10 @@ VGMSTREAM * init_vgmstream_thp(STREAMFILE *streamFile) {
|
||||
}
|
||||
|
||||
vgmstream->full_block_size = read_32bitBE(0x18,streamFile); /* block size of current block, changes every time */
|
||||
thp_block_update(start_offset,vgmstream);
|
||||
block_update_thp(start_offset,vgmstream);
|
||||
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_thp_blocked;
|
||||
vgmstream->layout_type = layout_blocked_thp;
|
||||
vgmstream->meta_type = meta_THP;
|
||||
|
||||
return vgmstream;
|
||||
|
@ -168,6 +168,8 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) {
|
||||
coding = coding_DVI_IMA_int;
|
||||
if (coding == coding_IMA)
|
||||
coding = coding_IMA_int;
|
||||
if (coding == coding_AICA)
|
||||
coding = coding_AICA_int;
|
||||
}
|
||||
|
||||
/* to avoid endless loops */
|
||||
@ -176,7 +178,8 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) {
|
||||
coding == coding_PSX_badflags ||
|
||||
coding == coding_IMA_int ||
|
||||
coding == coding_DVI_IMA_int ||
|
||||
coding == coding_SDX2_int) ) {
|
||||
coding == coding_SDX2_int ||
|
||||
coding == coding_AICA_int) ) {
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
@ -184,7 +187,7 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) {
|
||||
}
|
||||
|
||||
/* setup adpcm */
|
||||
if (coding == coding_AICA) {
|
||||
if (coding == coding_AICA || coding == coding_AICA_int) {
|
||||
int i;
|
||||
for (i=0;i<vgmstream->channels;i++) {
|
||||
vgmstream->ch[i].adpcm_step_index = 0x7f;
|
||||
@ -382,14 +385,14 @@ static STREAMFILE * open_txth(STREAMFILE * streamFile) {
|
||||
STREAMFILE * streamText;
|
||||
|
||||
/* try "(path/)(name.ext).txth" */
|
||||
if (!get_streamfile_name(streamFile,filename,PATH_LIMIT)) goto fail;
|
||||
get_streamfile_name(streamFile,filename,PATH_LIMIT);
|
||||
strcat(filename, ".txth");
|
||||
streamText = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (streamText) return streamText;
|
||||
|
||||
/* try "(path/)(.ext).txth" */
|
||||
if (!get_streamfile_path(streamFile,filename,PATH_LIMIT)) goto fail;
|
||||
if (!get_streamfile_ext(streamFile,fileext,PATH_LIMIT)) goto fail;
|
||||
get_streamfile_path(streamFile,filename,PATH_LIMIT);
|
||||
get_streamfile_ext(streamFile,fileext,PATH_LIMIT);
|
||||
strcat(filename,".");
|
||||
strcat(filename, fileext);
|
||||
strcat(filename, ".txth");
|
||||
@ -397,14 +400,13 @@ static STREAMFILE * open_txth(STREAMFILE * streamFile) {
|
||||
if (streamText) return streamText;
|
||||
|
||||
/* try "(path/).txth" */
|
||||
if (!get_streamfile_path(streamFile,filename,PATH_LIMIT)) goto fail;
|
||||
get_streamfile_path(streamFile,filename,PATH_LIMIT);
|
||||
strcat(filename, ".txth");
|
||||
streamText = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (streamText) return streamText;
|
||||
|
||||
fail:
|
||||
/* not found */
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Simple text parser of "key = value" lines.
|
||||
|
@ -90,7 +90,7 @@ VGMSTREAM * init_vgmstream_ubi_sb(STREAMFILE *streamFile) {
|
||||
if (sb.autodetect_external) { /* works most of the time but could give false positives */
|
||||
VGM_LOG("UBI SB: autodetecting external stream '%s'\n", sb.stream_name);
|
||||
|
||||
streamData = open_stream_name(streamFile,sb.stream_name);
|
||||
streamData = open_streamfile_by_filename(streamFile,sb.stream_name);
|
||||
if (!streamData) {
|
||||
streamData = streamFile; /* assume internal */
|
||||
if (sb.stream_size > get_streamfile_size(streamData)) {
|
||||
@ -102,7 +102,7 @@ VGMSTREAM * init_vgmstream_ubi_sb(STREAMFILE *streamFile) {
|
||||
}
|
||||
}
|
||||
else if (sb.is_external) {
|
||||
streamData = open_stream_name(streamFile,sb.stream_name);
|
||||
streamData = open_streamfile_by_filename(streamFile,sb.stream_name);
|
||||
if (!streamData) {
|
||||
VGM_LOG("UBI SB: external stream '%s' not found\n", sb.stream_name);
|
||||
goto fail;
|
||||
@ -674,7 +674,7 @@ static int config_sb_header_version(ubi_sb_header * sb, STREAMFILE *streamFile)
|
||||
|
||||
/* two games with same id; use project file as identifier */
|
||||
if (sb->version == 0x0012000C && is_sb4) {
|
||||
STREAMFILE * streamTest = open_stream_name(streamFile, "BIAAUDIO.SP4");
|
||||
STREAMFILE * streamTest = open_streamfile_by_filename(streamFile, "BIAAUDIO.SP4");
|
||||
if (streamTest) {
|
||||
is_biadd_psp = 1;
|
||||
close_streamfile(streamTest);
|
||||
|
@ -42,7 +42,7 @@ VGMSTREAM * init_vgmstream_vs(STREAMFILE *streamFile) {
|
||||
}
|
||||
#endif
|
||||
|
||||
vgmstream->layout_type = layout_vs_blocked;
|
||||
vgmstream->layout_type = layout_blocked_vs;
|
||||
vgmstream->meta_type = meta_VS;
|
||||
|
||||
|
||||
@ -55,15 +55,15 @@ VGMSTREAM * init_vgmstream_vs(STREAMFILE *streamFile) {
|
||||
}
|
||||
|
||||
/* Calc num_samples */
|
||||
vs_block_update(start_offset,vgmstream);
|
||||
block_update_vs(start_offset,vgmstream);
|
||||
vgmstream->num_samples=0;
|
||||
|
||||
do {
|
||||
vgmstream->num_samples += vgmstream->current_block_size*28/16;
|
||||
vs_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
block_update_vs(vgmstream->next_block_offset,vgmstream);
|
||||
} while (vgmstream->next_block_offset<get_streamfile_size(streamFile));
|
||||
|
||||
vs_block_update(start_offset,vgmstream);
|
||||
block_update_vs(start_offset,vgmstream);
|
||||
|
||||
|
||||
return vgmstream;
|
||||
|
@ -100,7 +100,7 @@ VGMSTREAM * init_vgmstream_ws_aud(STREAMFILE *streamFile) {
|
||||
vgmstream->meta_type = meta_WS_AUD_old;
|
||||
}
|
||||
|
||||
vgmstream->layout_type = layout_ws_aud_blocked;
|
||||
vgmstream->layout_type = layout_blocked_ws_aud;
|
||||
|
||||
/* open the file for reading by each channel */
|
||||
{
|
||||
@ -118,9 +118,9 @@ VGMSTREAM * init_vgmstream_ws_aud(STREAMFILE *streamFile) {
|
||||
|
||||
/* start me up */
|
||||
if (new_type) {
|
||||
ws_aud_block_update(0xc,vgmstream);
|
||||
block_update_ws_aud(0xc,vgmstream);
|
||||
} else {
|
||||
ws_aud_block_update(0x8,vgmstream);
|
||||
block_update_ws_aud(0x8,vgmstream);
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
|
@ -38,7 +38,7 @@ VGMSTREAM * init_vgmstream_x360_tra(STREAMFILE *streamFile) {
|
||||
|
||||
vgmstream->coding_type = coding_DVI_IMA_int;
|
||||
vgmstream->num_samples = (int32_t)(get_streamfile_size(streamFile) - ((get_streamfile_size(streamFile)/0x204)*4));
|
||||
vgmstream->layout_type = layout_tra_blocked;
|
||||
vgmstream->layout_type = layout_blocked_tra;
|
||||
|
||||
vgmstream->meta_type = meta_X360_TRA;
|
||||
|
||||
@ -51,7 +51,7 @@ VGMSTREAM * init_vgmstream_x360_tra(STREAMFILE *streamFile) {
|
||||
}
|
||||
}
|
||||
|
||||
tra_block_update(0,vgmstream);
|
||||
block_update_tra(0,vgmstream);
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
|
@ -31,7 +31,7 @@ VGMSTREAM * init_vgmstream_xbox_matx(STREAMFILE *streamFile) {
|
||||
vgmstream->sample_rate = read_16bitLE(0x06,streamFile) & 0xffff;
|
||||
|
||||
vgmstream->coding_type = coding_XBOX_IMA;
|
||||
vgmstream->layout_type = layout_matx_blocked;
|
||||
vgmstream->layout_type = layout_blocked_matx;
|
||||
vgmstream->meta_type = meta_XBOX_MATX;
|
||||
|
||||
/* open the file for reading by each channel */
|
||||
@ -43,15 +43,15 @@ VGMSTREAM * init_vgmstream_xbox_matx(STREAMFILE *streamFile) {
|
||||
}
|
||||
|
||||
/* Calc num_samples */
|
||||
matx_block_update(0,vgmstream);
|
||||
block_update_matx(0,vgmstream);
|
||||
vgmstream->num_samples=0;
|
||||
|
||||
do {
|
||||
vgmstream->num_samples += vgmstream->current_block_size/36*64;
|
||||
matx_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
block_update_matx(vgmstream->next_block_offset,vgmstream);
|
||||
} while (vgmstream->next_block_offset<get_streamfile_size(streamFile));
|
||||
|
||||
matx_block_update(0,vgmstream);
|
||||
block_update_matx(0,vgmstream);
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
|
@ -37,13 +37,13 @@ VGMSTREAM * init_vgmstream_xbox_xvas(STREAMFILE *streamFile) {
|
||||
}
|
||||
|
||||
vgmstream->coding_type = coding_XBOX_IMA;
|
||||
vgmstream->layout_type = layout_xvas_blocked;
|
||||
vgmstream->layout_type = layout_blocked_xvas;
|
||||
vgmstream->meta_type = meta_XBOX_XVAS;
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, streamFile, start_offset))
|
||||
goto fail;
|
||||
|
||||
xvas_block_update(start_offset,vgmstream);
|
||||
block_update_xvas(start_offset,vgmstream);
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
|
@ -41,7 +41,7 @@ VGMSTREAM * init_vgmstream_xnb(STREAMFILE *streamFile) {
|
||||
{
|
||||
char reader_name[255+1];
|
||||
off_t current_offset = 0x0a;
|
||||
int reader_string_len;
|
||||
size_t reader_string_len;
|
||||
uint32_t fmt_chunk_size;
|
||||
const char * type_sound = "Microsoft.Xna.Framework.Content.SoundEffectReader"; /* partial "fmt" chunk or XMA */
|
||||
//const char * type_song = "Microsoft.Xna.Framework.Content.SongReader"; /* just references a companion .wma */
|
||||
@ -76,6 +76,7 @@ VGMSTREAM * init_vgmstream_xnb(STREAMFILE *streamFile) {
|
||||
codec = read_16bit(current_offset+0x00, streamFile);
|
||||
channel_count = read_16bit(current_offset+0x02, streamFile);
|
||||
sample_rate = read_32bit(current_offset+0x04, streamFile);
|
||||
/* 0x08: byte rate */
|
||||
block_size = read_16bit(current_offset+0x0c, streamFile);
|
||||
bps = read_16bit(current_offset+0x0e, streamFile);
|
||||
|
||||
@ -102,6 +103,10 @@ VGMSTREAM * init_vgmstream_xnb(STREAMFILE *streamFile) {
|
||||
|
||||
switch (codec) {
|
||||
case 0x01: /* Dragon's Blade (Android) */
|
||||
/* null in Metagalactic Blitz (PC) */
|
||||
if (!block_size)
|
||||
block_size = (bps == 8 ? 0x01 : 0x02) * channel_count;
|
||||
|
||||
vgmstream->coding_type = bps == 8 ? coding_PCM8_U_int : coding_PCM16LE;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = block_size / channel_count;
|
||||
@ -109,6 +114,7 @@ VGMSTREAM * init_vgmstream_xnb(STREAMFILE *streamFile) {
|
||||
break;
|
||||
|
||||
case 0x02: /* White Noise Online (PC) */
|
||||
if (!block_size) goto fail;
|
||||
vgmstream->coding_type = coding_MSADPCM;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->interleave_block_size = block_size;
|
||||
@ -116,6 +122,7 @@ VGMSTREAM * init_vgmstream_xnb(STREAMFILE *streamFile) {
|
||||
break;
|
||||
|
||||
case 0x11:
|
||||
if (!block_size) goto fail;
|
||||
vgmstream->coding_type = coding_MS_IMA;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->interleave_block_size = block_size;
|
||||
|
@ -534,13 +534,13 @@ fail:
|
||||
|
||||
/* try to get the stream name in the .xwb, though they are very rarely included */
|
||||
static int get_xwb_name(char * buf, size_t maxsize, int target_subsong, xwb_header * xwb, STREAMFILE *streamFile) {
|
||||
int read;
|
||||
size_t read;
|
||||
|
||||
if (!xwb->names_offset || !xwb->names_size || xwb->names_entry_size > maxsize)
|
||||
goto fail;
|
||||
|
||||
read = read_string(buf,xwb->names_entry_size, xwb->names_offset + xwb->names_entry_size*(target_subsong-1),streamFile);
|
||||
if (read <= 0) goto fail;
|
||||
if (read == 0) goto fail;
|
||||
|
||||
return 1;
|
||||
|
||||
@ -601,7 +601,7 @@ static int get_xsb_name(char * buf, size_t maxsize, int target_subsong, xwb_head
|
||||
xsb_header xsb = {0};
|
||||
|
||||
|
||||
streamFile = open_stream_ext(streamXwb, "xsb");
|
||||
streamFile = open_streamfile_by_ext(streamXwb, "xsb");
|
||||
if (!streamFile) goto fail;
|
||||
|
||||
/* check header */
|
||||
|
159
src/streamfile.c
159
src/streamfile.c
@ -383,16 +383,22 @@ typedef struct {
|
||||
STREAMFILE sf;
|
||||
|
||||
STREAMFILE *inner_sf;
|
||||
void* data;
|
||||
void* data; /* state for custom reads, malloc'ed + copied on open (to re-open streamfiles cleanly) */
|
||||
size_t data_size;
|
||||
size_t (*read_callback)(STREAMFILE *, uint8_t *, off_t, size_t, void*);
|
||||
size_t (*read_callback)(STREAMFILE *, uint8_t *, off_t, size_t, void*); /* custom read to modify data before copying into buffer */
|
||||
size_t (*size_callback)(STREAMFILE *, void*); /* size when custom reads make data smaller/bigger than underlying streamfile */
|
||||
//todo would need to make sure re-opened streamfiles work with this, maybe should use init_data_callback per call
|
||||
//size_t (*close_data_callback)(STREAMFILE *, void*); /* called during close, allows to free stuff in data */
|
||||
} IO_STREAMFILE;
|
||||
|
||||
static size_t io_read(IO_STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length) {
|
||||
return streamfile->read_callback(streamfile->inner_sf, dest, offset, length, streamfile->data);
|
||||
}
|
||||
static size_t io_get_size(IO_STREAMFILE *streamfile) {
|
||||
return streamfile->inner_sf->get_size(streamfile->inner_sf); /* default */
|
||||
if (streamfile->size_callback)
|
||||
return streamfile->size_callback(streamfile->inner_sf, streamfile->data);
|
||||
else
|
||||
return streamfile->inner_sf->get_size(streamfile->inner_sf); /* default */
|
||||
}
|
||||
static off_t io_get_offset(IO_STREAMFILE *streamfile) {
|
||||
return streamfile->inner_sf->get_offset(streamfile->inner_sf); /* default */
|
||||
@ -406,7 +412,7 @@ static void io_get_realname(IO_STREAMFILE *streamfile, char *buffer, size_t leng
|
||||
static STREAMFILE *io_open(IO_STREAMFILE *streamfile, const char * const filename, size_t buffersize) {
|
||||
//todo should have some flag to decide if opening other files with IO
|
||||
STREAMFILE *new_inner_sf = streamfile->inner_sf->open(streamfile->inner_sf,filename,buffersize);
|
||||
return open_io_streamfile(new_inner_sf, streamfile->data, streamfile->data_size, streamfile->read_callback);
|
||||
return open_io_streamfile(new_inner_sf, streamfile->data, streamfile->data_size, streamfile->read_callback, streamfile->size_callback);
|
||||
}
|
||||
static void io_close(IO_STREAMFILE *streamfile) {
|
||||
streamfile->inner_sf->close(streamfile->inner_sf);
|
||||
@ -414,7 +420,7 @@ static void io_close(IO_STREAMFILE *streamfile) {
|
||||
free(streamfile);
|
||||
}
|
||||
|
||||
STREAMFILE *open_io_streamfile(STREAMFILE *streamfile, void* data, size_t data_size, void* read_callback) {
|
||||
STREAMFILE *open_io_streamfile(STREAMFILE *streamfile, void* data, size_t data_size, void* read_callback, void* size_callback) {
|
||||
IO_STREAMFILE *this_sf;
|
||||
|
||||
if (!streamfile) return NULL;
|
||||
@ -444,6 +450,7 @@ STREAMFILE *open_io_streamfile(STREAMFILE *streamfile, void* data, size_t data_s
|
||||
}
|
||||
this_sf->data_size = data_size;
|
||||
this_sf->read_callback = read_callback;
|
||||
this_sf->size_callback = size_callback;
|
||||
|
||||
return &this_sf->sf;
|
||||
}
|
||||
@ -684,6 +691,37 @@ fail:
|
||||
|
||||
/* **************************************************** */
|
||||
|
||||
STREAMFILE * open_streamfile_by_ext(STREAMFILE *streamFile, const char * ext) {
|
||||
char filename_ext[PATH_LIMIT];
|
||||
|
||||
streamFile->get_name(streamFile,filename_ext,sizeof(filename_ext));
|
||||
strcpy(filename_ext + strlen(filename_ext) - strlen(filename_extension(filename_ext)), ext);
|
||||
|
||||
return streamFile->open(streamFile,filename_ext,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
STREAMFILE * open_streamfile_by_filename(STREAMFILE *streamFile, const char * name) {
|
||||
char foldername[PATH_LIMIT];
|
||||
char filename[PATH_LIMIT];
|
||||
const char *path;
|
||||
|
||||
streamFile->get_name(streamFile,foldername,sizeof(foldername));
|
||||
|
||||
path = strrchr(foldername,DIR_SEPARATOR);
|
||||
if (path!=NULL) path = path+1;
|
||||
|
||||
if (path) {
|
||||
strcpy(filename, foldername);
|
||||
filename[path-foldername] = '\0';
|
||||
strcat(filename, name);
|
||||
} else {
|
||||
strcpy(filename, name);
|
||||
}
|
||||
|
||||
return streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
|
||||
/* 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.
|
||||
*
|
||||
@ -740,17 +778,17 @@ size_t get_streamfile_text_line(int dst_length, char * dst, off_t offset, STREAM
|
||||
}
|
||||
|
||||
|
||||
/* reads a c-string, up to maxsize or NULL, returning size. buf is optional. */
|
||||
int read_string(char * buf, size_t maxsize, off_t offset, STREAMFILE *streamFile) {
|
||||
int i;
|
||||
/* reads a c-string (ANSI only), up to maxsize or NULL, returning size. buf is optional (works as get_string_size). */
|
||||
size_t read_string(char * buf, size_t maxsize, off_t offset, STREAMFILE *streamFile) {
|
||||
size_t pos;
|
||||
|
||||
for (i=0; i < maxsize; i++) {
|
||||
char c = read_8bit(offset + i, streamFile);
|
||||
if (buf) buf[i] = c;
|
||||
for (pos = 0; pos < maxsize; pos++) {
|
||||
char c = read_8bit(offset + pos, streamFile);
|
||||
if (buf) buf[pos] = c;
|
||||
if (c == '\0')
|
||||
return i;
|
||||
if (i+1 == maxsize) { /* null at maxsize and don't validate (expected to be garbage) */
|
||||
if (buf) buf[i] = '\0';
|
||||
return pos;
|
||||
if (pos+1 == maxsize) { /* null at maxsize and don't validate (expected to be garbage) */
|
||||
if (buf) buf[pos] = '\0';
|
||||
return maxsize;
|
||||
}
|
||||
if (c < 0x20 || c > 0xA5)
|
||||
@ -762,37 +800,6 @@ fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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];
|
||||
|
||||
streamFile->get_name(streamFile,filename_ext,sizeof(filename_ext));
|
||||
strcpy(filename_ext + strlen(filename_ext) - strlen(filename_extension(filename_ext)), ext);
|
||||
|
||||
return streamFile->open(streamFile,filename_ext,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
/* 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];
|
||||
const char *path;
|
||||
|
||||
streamFile->get_name(streamFile,foldername,sizeof(foldername));
|
||||
|
||||
path = strrchr(foldername,DIR_SEPARATOR);
|
||||
if (path!=NULL) path = path+1;
|
||||
|
||||
if (path) {
|
||||
strcpy(filename, foldername);
|
||||
filename[path-foldername] = '\0';
|
||||
strcat(filename, name);
|
||||
} else {
|
||||
strcpy(filename, name);
|
||||
}
|
||||
|
||||
return streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
/* Opens a file containing decryption keys and copies to buffer.
|
||||
* Tries combinations of keynames based on the original filename.
|
||||
@ -869,53 +876,10 @@ fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* open file containing looping data and copy to buffer
|
||||
*
|
||||
* returns true if found and copied
|
||||
*/
|
||||
int read_pos_file(uint8_t * buf, size_t bufsize, STREAMFILE *streamFile) {
|
||||
char posname[PATH_LIMIT];
|
||||
char filename[PATH_LIMIT];
|
||||
/*size_t bytes_read;*/
|
||||
STREAMFILE * streamFilePos= NULL;
|
||||
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
|
||||
if (strlen(filename)+4 > sizeof(posname)) goto fail;
|
||||
|
||||
/* try to open a posfile using variations: "(name.ext).pos" */
|
||||
{
|
||||
strcpy(posname, filename);
|
||||
strcat(posname, ".pos");
|
||||
streamFilePos = streamFile->open(streamFile,posname,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (streamFilePos) goto found;
|
||||
|
||||
goto fail;
|
||||
}
|
||||
|
||||
found:
|
||||
//if (get_streamfile_size(streamFilePos) != bufsize) goto fail;
|
||||
|
||||
/* allow pos files to be of different sizes in case of new features, just fill all we can */
|
||||
memset(buf, 0, bufsize);
|
||||
read_streamfile(buf, 0, bufsize, streamFilePos);
|
||||
|
||||
close_streamfile(streamFilePos);
|
||||
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
if (streamFilePos) close_streamfile(streamFilePos);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* checks if the stream filename is one of the extensions (comma-separated, ex. "adx" or "adx,aix")
|
||||
*
|
||||
* returns 0 on failure
|
||||
* Checks if the stream filename is one of the extensions (comma-separated, ex. "adx" or "adx,aix").
|
||||
* Empty is ok to accept files without extension ("", "adx,,aix"). Returns 0 on failure
|
||||
*/
|
||||
int check_extensions(STREAMFILE *streamFile, const char * cmp_exts) {
|
||||
char filename[PATH_LIMIT];
|
||||
@ -990,14 +954,15 @@ int find_chunk(STREAMFILE *streamFile, uint32_t chunk_id, off_t start_offset, in
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_streamfile_name(STREAMFILE *streamFile, char * buffer, size_t size) {
|
||||
void get_streamfile_name(STREAMFILE *streamFile, char * buffer, size_t size) {
|
||||
streamFile->get_name(streamFile,buffer,size);
|
||||
return 1;
|
||||
}
|
||||
int get_streamfile_filename(STREAMFILE *streamFile, char * buffer, size_t size) {
|
||||
/* copies the filename without path */
|
||||
void get_streamfile_filename(STREAMFILE *streamFile, char * buffer, size_t size) {
|
||||
char foldername[PATH_LIMIT];
|
||||
const char *path;
|
||||
|
||||
|
||||
streamFile->get_name(streamFile,foldername,sizeof(foldername));
|
||||
|
||||
//todo Windows CMD accepts both \\ and /, better way to handle this?
|
||||
@ -1013,9 +978,8 @@ int get_streamfile_filename(STREAMFILE *streamFile, char * buffer, size_t size)
|
||||
} else {
|
||||
strcpy(buffer, foldername);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
int get_streamfile_path(STREAMFILE *streamFile, char * buffer, size_t size) {
|
||||
void get_streamfile_path(STREAMFILE *streamFile, char * buffer, size_t size) {
|
||||
const char *path;
|
||||
|
||||
streamFile->get_name(streamFile,buffer,size);
|
||||
@ -1028,11 +992,8 @@ int get_streamfile_path(STREAMFILE *streamFile, char * buffer, size_t size) {
|
||||
} else {
|
||||
buffer[0] = '\0';
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
int get_streamfile_ext(STREAMFILE *streamFile, char * filename, size_t size) {
|
||||
void get_streamfile_ext(STREAMFILE *streamFile, char * filename, size_t size) {
|
||||
streamFile->get_name(streamFile,filename,size);
|
||||
strcpy(filename, filename_extension(filename));
|
||||
return 1;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user