Merge pull request #210 from bnnm/aica-layers-eatrax-misc

AICA, layers, EATrax, misc
This commit is contained in:
Christopher Snowhill 2018-03-31 17:54:33 -07:00 committed by GitHub
commit 3ef2f62ad1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
103 changed files with 2577 additions and 1266 deletions

View File

@ -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.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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) {

View File

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

View File

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

View File

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

View File

@ -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(

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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++) {

View File

@ -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(

View File

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

View File

@ -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
View 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]);
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -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" />

View File

@ -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">

View File

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

View File

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

View File

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

View File

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

View File

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

View 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_ */

View File

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

View File

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

View File

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

View File

@ -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)) {

View File

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

View File

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

View File

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

View 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_ */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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"*/

View File

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

View File

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

View File

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

View File

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

View File

@ -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))

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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:

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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_ */

View File

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

View File

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

View File

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

View File

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

View File

@ -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.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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:

View File

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

View File

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

View File

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