Merge pull request #456 from bnnm/rsd-psf-itl

rsd psf itl
This commit is contained in:
bnnm 2019-08-12 22:09:03 +02:00 committed by GitHub
commit c7afd0d72a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 1010 additions and 1584 deletions

View File

@ -191,7 +191,7 @@ left together.
Similarly some formats split header and/or data in separate files (.sgh+sgd,
.wav.str+.wav, (file)_L.dsp+(file)_R.dsp, etc). vgmstream will also detect
and use those as needed and must be tegether, even if only one of the two
and use those as needed and must be together, even if only one of the two
will be used to play.
.pos is a small file with 32 bit little endian values: loop start sample
@ -322,7 +322,7 @@ are used in few games.
- Nintendo AFC ADPCM
- ITU-T G.721
- CD-ROM XA ADPCM
- Sony PSX ADPCM a.k.a VAG (standard, badflags, configurable)
- Sony PSX ADPCM a.k.a VAG (standard, badflags, configurable, Pivotal)
- Sony HEVAG
- Electronic Arts EA-XA (stereo, mono, Maxis)
- Electronic Arts EA-XAS (v0, v1)

View File

@ -639,6 +639,12 @@ int main(int argc, char **argv) {
while ((opt = getopt(argc, argv, "-D:F:L:M:S:b:d:f:o:@:hrv")) != -1) {
switch (opt) {
case 1:
if (play_file(optarg, &par)) {
status = 1;
goto done;
}
break;
case '@':
if (play_playlist(optarg, &par)) {
status = 1;
@ -689,9 +695,12 @@ int main(int argc, char **argv) {
verbose = 1;
break;
default:
VGM_LOG("vgmstream123: unknown opt %x", opt);
goto done;
}
}
/* try to read infile here in case getopt didn't pass "1" to the above switch I guess */
argc -= optind;
argv += optind;

View File

@ -83,6 +83,7 @@ size_t pcm_bytes_to_samples(size_t bytes, int channels, int bits_per_sample);
/* psx_decoder */
void decode_psx(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int is_badflags);
void decode_psx_configurable(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int frame_size);
void decode_psx_pivotal(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int frame_size);
int ps_find_loop_offsets(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, size_t interleave, int32_t * out_loop_start, int32_t * out_loop_end);
int ps_find_loop_offsets_full(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, size_t interleave, int32_t * out_loop_start, int32_t * out_loop_end);
size_t ps_find_padding(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, size_t interleave, int discard_empty);
@ -108,10 +109,10 @@ void decode_ea_xas_v0(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspa
void decode_ea_xas_v1(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
/* sdx2_decoder */
void decode_sdx2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_sdx2_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_cbd2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_cbd2_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_sdx2(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_sdx2_int(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_cbd2(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_cbd2_int(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
/* ws_decoder */
void decode_ws(VGMSTREAM * vgmstream, int channel, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);

View File

@ -3,11 +3,11 @@
/* PS-ADPCM table, defined as rational numbers (as in the spec) */
static const double ps_adpcm_coefs_f[5][2] = {
{ 0.0 , 0.0 },
{ 60.0 / 64.0 , 0.0 },
{ 115.0 / 64.0 , -52.0 / 64.0 },
{ 98.0 / 64.0 , -55.0 / 64.0 },
{ 122.0 / 64.0 , -60.0 / 64.0 },
{ 0.0 , 0.0 }, //{ 0.0 , 0.0 },
{ 0.9375 , 0.0 }, //{ 60.0 / 64.0 , 0.0 },
{ 1.796875 , -0.8125 }, //{ 115.0 / 64.0 , -52.0 / 64.0 },
{ 1.53125 , -0.859375 }, //{ 98.0 / 64.0 , -55.0 / 64.0 },
{ 1.90625 , -0.9375 }, //{ 122.0 / 64.0 , -60.0 / 64.0 },
};
/* PS-ADPCM table, defined as spec_coef*64 (for int implementations) */
@ -101,7 +101,7 @@ void decode_psx(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing
/* PS-ADPCM with configurable frame size and no flag (int math version).
* Found in some PC/PS3 games (FF XI in sizes 3/5/9/41, Afrika in size 4, Blur/James Bond in size 33, etc).
* Found in some PC/PS3 games (FF XI in sizes 0x3/0x5/0x9/0x41, Afrika in size 0x4, Blur/James Bond in size 0x33, etc).
*
* Uses int math to decode, which seems more likely (based on FF XI PC's code in Moogle Toolbox). */
void decode_psx_configurable(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int frame_size) {
@ -114,7 +114,7 @@ void decode_psx_configurable(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int c
/* external interleave (variable size), mono */
bytes_per_frame = frame_size;
samples_per_frame = (bytes_per_frame - 0x01) * 2; /* always 28 */
samples_per_frame = (bytes_per_frame - 0x01) * 2;
frames_in = first_sample / samples_per_frame;
first_sample = first_sample % samples_per_frame;
@ -152,6 +152,56 @@ void decode_psx_configurable(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int c
stream->adpcm_history2_32 = hist2;
}
/* PS-ADPCM from Pivotal games, exactly like psx_cfg but with float math (reverse engineered from the exe) */
void decode_psx_pivotal(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int frame_size) {
off_t frame_offset;
int i, frames_in, sample_count = 0;
size_t bytes_per_frame, samples_per_frame;
uint8_t coef_index, shift_factor;
int32_t hist1 = stream->adpcm_history1_32;
int32_t hist2 = stream->adpcm_history2_32;
float scale;
/* external interleave (variable size), mono */
bytes_per_frame = frame_size;
samples_per_frame = (bytes_per_frame - 0x01) * 2;
frames_in = first_sample / samples_per_frame;
first_sample = first_sample % samples_per_frame;
/* parse frame header */
frame_offset = stream->offset + bytes_per_frame*frames_in;
coef_index = ((uint8_t)read_8bit(frame_offset+0x00,stream->streamfile) >> 4) & 0xf;
shift_factor = ((uint8_t)read_8bit(frame_offset+0x00,stream->streamfile) >> 0) & 0xf;
VGM_ASSERT_ONCE(coef_index > 5 || shift_factor > 12, "PS-ADPCM: incorrect coefs/shift at %x\n", (uint32_t)frame_offset);
if (coef_index > 5) /* just in case */
coef_index = 5;
if (shift_factor > 12) /* same */
shift_factor = 12;
scale = (float)(1.0 / (double)(1 << shift_factor));
/* decode nibbles */
for (i = first_sample; i < first_sample + samples_to_do; i++) {
int32_t sample = 0;
uint8_t nibbles = (uint8_t)read_8bit(frame_offset+0x01+i/2,stream->streamfile);
sample = !(i&1) ? /* low nibble first */
(nibbles >> 0) & 0x0f :
(nibbles >> 4) & 0x0f;
sample = (int16_t)((sample << 12) & 0xf000); /* 16b sign extend + default scale */
sample = sample*scale + ps_adpcm_coefs_f[coef_index][0]*hist1 + ps_adpcm_coefs_f[coef_index][1]*hist2; /* actually substracts negative coefs but whatevs */
outbuf[sample_count] = clamp16(sample);
sample_count += channelspacing;
hist2 = hist1;
hist1 = sample; /* not clamped but no difference */
}
stream->adpcm_history1_32 = hist1;
stream->adpcm_history2_32 = hist2;
}
/* Find loop samples in PS-ADPCM data and return if the file loops.
*
@ -339,7 +389,8 @@ size_t ps_bytes_to_samples(size_t bytes, int channels) {
}
size_t ps_cfg_bytes_to_samples(size_t bytes, size_t frame_size, int channels) {
return bytes / channels / frame_size * 28;
int samples_per_frame = (frame_size - 0x01) * 2;
return bytes / channels / frame_size * samples_per_frame;
}
/* test PS-ADPCM frames for correctness */

View File

@ -5,7 +5,7 @@
/* SDX2 - 2:1 Squareroot-delta-exact compression */
/* CBD2 - 2:1 Cuberoot-delta-exact compression (from the unreleased 3DO M2) */
/* for (i=-128;i<128;i++) squares[i+128]=i<0?(-i*i)*2:(i*i)*2; */
/* for (i=-128;i<128;i++) { squares[i+128] = i<0?(-i*i)*2:(i*i)*2; } */
static int16_t squares[256] = {
-32768,-32258,-31752,-31250,-30752,-30258,-29768,-29282,-28800,-28322,-27848,
-27378,-26912,-26450,-25992,-25538,-25088,-24642,-24200,-23762,-23328,-22898,
@ -33,11 +33,7 @@ static int16_t squares[256] = {
31250, 31752, 32258
};
//for (i=-128;i<128;i++)
//{
// double j = (i/2)/2.0;
// cubes[i+128]=floor(j*j*j);
//}
/* for (i=-128;i<128;i++) { double j = (i/2)/2.0; cubes[i+128] = floor(j*j*j); } */
static int16_t cubes[256] = {
-32768,-31256,-31256,-29791,-29791,-28373,-28373,-27000,-27000,-25672,-25672,
-24389,-24389,-23149,-23149,-21952,-21952,-20797,-20797,-19683,-19683,-18610,
@ -62,15 +58,16 @@ static int16_t cubes[256]={
12167, 12167, 12978, 12978, 13824, 13824, 14706, 14706, 15625, 15625, 16581,
16581, 17576, 17576, 18610, 18610, 19683, 19683, 20797, 20797, 21952, 21952,
23149, 23149, 24389, 24389, 25672, 25672, 27000, 27000, 28373, 28373, 29791,
29791, 31256, 31256};
static void decode_delta_exact(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int16_t * table) {
29791, 31256, 31256
};
static void decode_delta_exact(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int16_t * table) {
int32_t hist = stream->adpcm_history1_32;
int i;
int32_t sample_count;
int32_t sample_count = 0;
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
for (i=first_sample; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
int8_t sample_byte = read_8bit(stream->offset+i,stream->streamfile);
int16_t sample;
@ -79,17 +76,17 @@ static void decode_delta_exact(VGMSTREAMCHANNEL * stream, sample * outbuf, int c
hist = outbuf[sample_count] = clamp16(sample);
}
stream->adpcm_history1_32 = hist;
}
static void decode_delta_exact_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int16_t * table) {
static void decode_delta_exact_int(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int16_t * table) {
int32_t hist = stream->adpcm_history1_32;
int i;
int32_t sample_count;
int32_t sample_count = 0;
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
for (i=first_sample; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
int8_t sample_byte = read_8bit(stream->offset+i*channelspacing,stream->streamfile);
int16_t sample;
@ -98,21 +95,22 @@ static void decode_delta_exact_int(VGMSTREAMCHANNEL * stream, sample * outbuf, i
hist = outbuf[sample_count] = clamp16(sample);
}
stream->adpcm_history1_32 = hist;
}
void decode_sdx2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
void decode_sdx2(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
decode_delta_exact(stream, outbuf, channelspacing, first_sample, samples_to_do, squares);
}
void decode_sdx2_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
void decode_sdx2_int(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
decode_delta_exact_int(stream, outbuf, channelspacing, first_sample, samples_to_do, squares);
}
void decode_cbd2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
void decode_cbd2(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
decode_delta_exact(stream, outbuf, channelspacing, first_sample, samples_to_do, cubes);
}
void decode_cbd2_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
void decode_cbd2_int(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
decode_delta_exact_int(stream, outbuf, channelspacing, first_sample, samples_to_do, cubes);
}

View File

@ -333,6 +333,7 @@ static const char* extension_list[] = {
"pona",
"pos",
"ps2stm", //fake extension for .stm (renamed? to be removed?)
"psf",
"psh", //fake extension for .vsv (to be removed)
"psnd",
"psw", //fake extension for .wam (renamed, to be removed)
@ -616,6 +617,7 @@ static const coding_info coding_info_list[] = {
{coding_PSX, "Playstation 4-bit ADPCM"},
{coding_PSX_badflags, "Playstation 4-bit ADPCM (bad flags)"},
{coding_PSX_cfg, "Playstation 4-bit ADPCM (configurable)"},
{coding_PSX_pivotal, "Playstation 4-bit ADPCM (Pivotal)"},
{coding_HEVAG, "Sony HEVAG 4-bit ADPCM"},
{coding_EA_XA, "Electronic Arts EA-XA 4-bit ADPCM v1"},
@ -832,7 +834,7 @@ static const meta_info meta_info_list[] = {
{meta_DSP_WSI, "Alone in the Dark .WSI header"},
{meta_AIFC, "Apple AIFF-C (Audio Interchange File Format) header"},
{meta_AIFF, "Apple AIFF (Audio Interchange File Format) header"},
{meta_STR_SNDS, ".str SNDS SHDR chunk"},
{meta_STR_SNDS, "3DO .str header"},
{meta_WS_AUD, "Westwood Studios .aud header"},
{meta_WS_AUD_old, "Westwood Studios .aud (old) header"},
{meta_PS2_IVB, "IVB/BVII header"},
@ -881,7 +883,7 @@ static const meta_info meta_info_list[] = {
{meta_SCD_PCM, "Lunar: Eternal Blue .PCM header"},
{meta_PS2_PCM, "Konami KCEJ East .PCM header"},
{meta_PS2_RKV, "Legacy of Kain - Blood Omen 2 RKV PS2 header"},
{meta_PS2_VAS, "Pro Baseball Spirits 5 VAS Header"},
{meta_PS2_VAS, "Konami .VAS header"},
{meta_PS2_TEC, "assumed TECMO badflagged stream by .tec extension"},
{meta_PS2_ENTH, ".enth Header"},
{meta_SDT, "High Voltage .sdt header"},
@ -904,24 +906,7 @@ static const meta_info meta_info_list[] = {
{meta_PS2_MIHB, "Sony MultiStream MIC header"},
{meta_DSP_WII_MUS, "mus header"},
{meta_WII_SNG, "SNG DSP Header"},
{meta_RSD2VAG, "Radical RSD2/VAG header"},
{meta_RSD2PCMB, "Radical RSD2/PCMB header"},
{meta_RSD2XADP, "Radical RSD2/XADP header"},
{meta_RSD3VAG, "Radical RSD3/VAG header"},
{meta_RSD3GADP, "Radical RSD3/GADP header"},
{meta_RSD3PCM, "Radical RSD3/PCM header"},
{meta_RSD3PCMB, "Radical RSD3/PCMB header"},
{meta_RSD4PCMB, "Radical RSD4/PCMB header"},
{meta_RSD4PCM, "Radical RSD4/PCM header"},
{meta_RSD4RADP, "Radical RSD4/RADP header"},
{meta_RSD4VAG, "Radical RSD4/VAG header"},
{meta_RSD6XADP, "Radical RSD6/XADP header"},
{meta_RSD6VAG, "Radical RSD6/VAG header"},
{meta_RSD6WADP, "Radical RSD6/WADP header"},
{meta_RSD6RADP, "Radical RSD6/RADP header"},
{meta_RSD6XMA, "Radical RSD6/XMA header"},
{meta_RSD6AT3P, "Radical RSD6/AT3+ header"},
{meta_RSD6WMA, "Radical RSD6/WMA header"},
{meta_RSD, "Radical RSD header"},
{meta_DC_ASD, "ASD Header"},
{meta_NAOMI_SPSD, "Naomi SPSD header"},
{meta_FFXI_BGW, "Square Enix .BGW header"},
@ -980,7 +965,6 @@ static const meta_info meta_info_list[] = {
{meta_PS2_VGV, "Rune: Viking Warlord VGV Header"},
{meta_NGC_GCUB, "GCub Header"},
{meta_NGC_SCK_DSP, "The Scorpion King SCK Header"},
{meta_NGC_SWD, "PSF + Standard DSP Headers"},
{meta_CAFF, "Apple Core Audio Format File header"},
{meta_PC_MXST, "Lego Island MxSt Header"},
{meta_SAB, "Team17 SAB header"},
@ -1063,7 +1047,6 @@ static const meta_info meta_info_list[] = {
{meta_PS2_HSF, "Lowrider 'HSF' header"},
{meta_PS3_IVAG, "PS3 'IVAG' Header"},
{meta_PS2_2PFS, "Konami 2PFS header"},
{meta_RSD6OOGV, "RSD6/OOGV Header"},
{meta_UBI_CKD, "Ubisoft CKD RIFF header"},
{meta_PS2_VBK, "PS2 VBK Header"},
{meta_OTM, "Otomedius OTM Header"},
@ -1205,6 +1188,8 @@ static const meta_info meta_info_list[] = {
{meta_SMACKER, "RAD Game Tools SMACKER header"},
{meta_MZRT, "id Software MZRT header"},
{meta_XAVS, "Reflections XAVS header"},
{meta_PSF, "Pivotal PSF header"},
{meta_DSP_ITL_i, "Infernal .ITL DSP header"},
};

View File

@ -8,19 +8,48 @@
* Incompatible with decoders that move offsets. */
void render_vgmstream_interleave(sample_t * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
int samples_written = 0;
int frame_size, samples_per_frame, samples_this_block;
int samples_per_frame, samples_this_block; /* used */
int samples_per_frame_d = 0, samples_this_block_d = 0; /* default */
int samples_per_frame_f = 0, samples_this_block_f = 0; /* first */
int samples_per_frame_l = 0, samples_this_block_l = 0; /* last */
int has_interleave_first = vgmstream->interleave_first_block_size && vgmstream->channels > 1;
int has_interleave_last = vgmstream->interleave_last_block_size && vgmstream->channels > 1;
frame_size = get_vgmstream_frame_size(vgmstream);
samples_per_frame = get_vgmstream_samples_per_frame(vgmstream);
samples_this_block = vgmstream->interleave_block_size / frame_size * samples_per_frame;
if (has_interleave_last &&
vgmstream->current_sample - vgmstream->samples_into_block + samples_this_block > vgmstream->num_samples) {
/* adjust values again if inside last interleave */
frame_size = get_vgmstream_shortframe_size(vgmstream);
samples_per_frame = get_vgmstream_samples_per_shortframe(vgmstream);
samples_this_block = vgmstream->interleave_last_block_size / frame_size * samples_per_frame;
/* setup */
{
int frame_size_d = get_vgmstream_frame_size(vgmstream);
samples_per_frame_d = get_vgmstream_samples_per_frame(vgmstream);
if (frame_size_d == 0 || samples_per_frame_d == 0) goto fail;
samples_this_block_d = vgmstream->interleave_block_size / frame_size_d * samples_per_frame_d;
}
if (has_interleave_first) {
int frame_size_f = get_vgmstream_frame_size(vgmstream);
samples_per_frame_f = get_vgmstream_samples_per_frame(vgmstream); //todo samples per shortframe
if (frame_size_f == 0 || samples_per_frame_f == 0) goto fail;
samples_this_block_f = vgmstream->interleave_first_block_size / frame_size_f * samples_per_frame_f;
}
if (has_interleave_last) {
int frame_size_l = get_vgmstream_shortframe_size(vgmstream);
samples_per_frame_l = get_vgmstream_samples_per_shortframe(vgmstream);
if (frame_size_l == 0 || samples_per_frame_l == 0) goto fail;
samples_this_block_l = vgmstream->interleave_last_block_size / frame_size_l * samples_per_frame_l;
}
/* set current values */
if (has_interleave_first &&
vgmstream->current_sample < samples_this_block_f) {
samples_per_frame = samples_per_frame_f;
samples_this_block = samples_this_block_f;
}
else if (has_interleave_last &&
vgmstream->current_sample - vgmstream->samples_into_block + samples_this_block_d > vgmstream->num_samples) {
samples_per_frame = samples_per_frame_l;
samples_this_block = samples_this_block_l;
}
else {
samples_per_frame = samples_per_frame_d;
samples_this_block = samples_this_block_d;
}
/* mono interleaved stream with no layout set, just behave like flat layout */
@ -28,18 +57,28 @@ void render_vgmstream_interleave(sample_t * buffer, int32_t sample_count, VGMSTR
samples_this_block = vgmstream->num_samples;
/* write samples */
while (samples_written < sample_count) {
int samples_to_do;
if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) {
/* handle looping, restore standard interleave sizes */
if (has_interleave_last) { /* assumes that won't loop back into a interleave_last */
frame_size = get_vgmstream_frame_size(vgmstream);
samples_per_frame = get_vgmstream_samples_per_frame(vgmstream);
samples_this_block = vgmstream->interleave_block_size / frame_size * samples_per_frame;
if (has_interleave_first &&
vgmstream->current_sample < samples_this_block_f) {
/* use first interleave*/
samples_per_frame = samples_per_frame_f;
samples_this_block = samples_this_block_f;
if (samples_this_block == 0 && vgmstream->channels == 1)
samples_this_block = vgmstream->num_samples;
}
else if (has_interleave_last) { /* assumes that won't loop back into a interleave_last */
samples_per_frame = samples_per_frame_d;
samples_this_block = samples_this_block_d;
if (samples_this_block == 0 && vgmstream->channels == 1)
samples_this_block = vgmstream->num_samples;
}
continue;
}
@ -48,9 +87,7 @@ void render_vgmstream_interleave(sample_t * buffer, int32_t sample_count, VGMSTR
samples_to_do = sample_count - samples_written;
if (samples_to_do == 0) { /* happens when interleave is not set */
VGM_LOG("layout_interleave: wrong samples_to_do found\n");
memset(buffer + samples_written*vgmstream->channels, 0, (sample_count - samples_written) * vgmstream->channels * sizeof(sample_t));
break;
goto fail;
}
decode_vgmstream(vgmstream, samples_written, samples_to_do, buffer);
@ -64,18 +101,34 @@ void render_vgmstream_interleave(sample_t * buffer, int32_t sample_count, VGMSTR
if (vgmstream->samples_into_block == samples_this_block) {
int ch;
if (has_interleave_last &&
vgmstream->current_sample + samples_this_block > vgmstream->num_samples) {
/* adjust values again if inside last interleave */
frame_size = get_vgmstream_shortframe_size(vgmstream);
samples_per_frame = get_vgmstream_samples_per_shortframe(vgmstream);
samples_this_block = vgmstream->interleave_last_block_size / frame_size * samples_per_frame;
if (has_interleave_first &&
vgmstream->current_sample == samples_this_block_f) {
/* restore standard frame size after going past first interleave */
samples_per_frame = samples_per_frame_d;
samples_this_block = samples_this_block_d;
if (samples_this_block == 0 && vgmstream->channels == 1)
samples_this_block = vgmstream->num_samples;
for (ch = 0; ch < vgmstream->channels; ch++) {
off_t skip = vgmstream->interleave_block_size*(vgmstream->channels-ch) +
vgmstream->interleave_last_block_size*ch;;
off_t skip =
vgmstream->interleave_first_skip*(vgmstream->channels-1-ch) +
vgmstream->interleave_first_block_size*(vgmstream->channels-ch) +
vgmstream->interleave_block_size*ch;
vgmstream->ch[ch].offset += skip;
}
}
else if (has_interleave_last &&
vgmstream->current_sample + samples_this_block > vgmstream->num_samples) {
/* adjust values again if inside last interleave */
samples_per_frame = samples_per_frame_l;
samples_this_block = samples_this_block_l;
if (samples_this_block == 0 && vgmstream->channels == 1)
samples_this_block = vgmstream->num_samples;
for (ch = 0; ch < vgmstream->channels; ch++) {
off_t skip =
vgmstream->interleave_block_size*(vgmstream->channels-ch) +
vgmstream->interleave_last_block_size*ch;
vgmstream->ch[ch].offset += skip;
}
}
@ -88,6 +141,9 @@ void render_vgmstream_interleave(sample_t * buffer, int32_t sample_count, VGMSTR
vgmstream->samples_into_block = 0;
}
}
return;
fail:
VGM_LOG("layout_interleave: wrong values found\n");
memset(buffer + samples_written*vgmstream->channels, 0, (sample_count - samples_written) * vgmstream->channels * sizeof(sample_t));
}

View File

@ -2,7 +2,7 @@
#include "../vgmstream.h"
#include "../mixing.h"
#define VGMSTREAM_MAX_SEGMENTS 255
#define VGMSTREAM_MAX_SEGMENTS 512
#define VGMSTREAM_SEGMENT_SAMPLE_BUFFER 8192

View File

@ -1369,6 +1369,10 @@
<File
RelativePath=".\meta\ps3_past.c"
>
</File>
<File
RelativePath=".\meta\psf.c"
>
</File>
<File
RelativePath=".\meta\sgxd.c"

View File

@ -195,6 +195,7 @@
<ClCompile Include="meta\ps2_wmus.c" />
<ClCompile Include="meta\ps3_ivag.c" />
<ClCompile Include="meta\ps3_past.c" />
<ClCompile Include="meta\psf.c" />
<ClCompile Include="meta\sgxd.c" />
<ClCompile Include="meta\sk_aud.c" />
<ClCompile Include="meta\vawx.c" />

View File

@ -1369,6 +1369,9 @@
<ClCompile Include="meta\ps3_past.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\psf.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\sgxd.c">
<Filter>meta\Source Files</Filter>
</ClCompile>

View File

@ -11,7 +11,8 @@ VGMSTREAM * init_vgmstream_adpcm_capcom(STREAMFILE *streamFile) {
/* checks */
if (!check_extensions(streamFile,"adpcm"))
/* .mca: Monster Hunter Generations Ultimate / XX */
if (!check_extensions(streamFile,"adpcm,mca"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x02000000)
goto fail;

View File

@ -31,7 +31,6 @@ VGMSTREAM * init_vgmstream_ngc_dsp_std_int(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_idsp_nus3(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_sadb(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_sadf(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ngc_swd(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_idsp_tt(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_idsp_nl(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_wii_wsd(STREAMFILE *streamFile);
@ -51,6 +50,7 @@ VGMSTREAM * init_vgmstream_dsp_itl_ch(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_dsp_adpy(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_dsp_adpx(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_dsp_ds2(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_dsp_itl(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_csmp(STREAMFILE *streamFile);
@ -240,6 +240,7 @@ VGMSTREAM * init_vgmstream_ps2_pcm(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ps2_rkv(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ps2_vas(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ps2_vas_container(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ps2_tec(STREAMFILE * streamFile);
@ -302,25 +303,7 @@ VGMSTREAM * init_vgmstream_ngc_pdt(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_wii_mus(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_rsd2vag(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_rsd2pcmb(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_rsd2xadp(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_rsd3pcm(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_rsd3pcmb(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_rsd3gadp(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_rsd3vag(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_rsd4pcmb(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_rsd4pcm(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_rsd4radp(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_rsd4vag(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_rsd6vag(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_rsd6wadp(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_rsd6xadp(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_rsd6radp(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_rsd6oogv(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_rsd6xma(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_rsd6at3p(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_rsd6wma(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_rsd(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_dc_asd(STREAMFILE * streamFile);
@ -871,4 +854,7 @@ VGMSTREAM * init_vgmstream_mzrt(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_xavs(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_psf_single(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_psf_segmented(STREAMFILE * streamFile);
#endif /*_META_H*/

View File

@ -79,6 +79,8 @@ typedef struct {
size_t header_spacing; /* distance between DSP header of other channels */
off_t start_offset; /* data start */
size_t interleave; /* distance between data of other channels */
size_t interleave_first; /* same, in the first block */
size_t interleave_first_skip; /* extra info */
size_t interleave_last; /* same, in the last block */
meta_t meta_type;
@ -208,6 +210,8 @@ static VGMSTREAM * init_vgmstream_dsp_common(STREAMFILE *streamFile, dsp_meta *d
if (dspm->interleave == 0 || vgmstream->coding_type == coding_NGC_DSP_subint)
vgmstream->layout_type = layout_none;
vgmstream->interleave_block_size = dspm->interleave;
vgmstream->interleave_first_block_size = dspm->interleave_first;
vgmstream->interleave_first_skip = dspm->interleave_first_skip;
vgmstream->interleave_last_block_size = dspm->interleave_last;
{
@ -690,33 +694,6 @@ fail:
return NULL;
}
/* SWD - PSF chunks + interleaved dsps [Conflict: Desert Storm 1 & 2] */
VGMSTREAM * init_vgmstream_ngc_swd(STREAMFILE *streamFile) {
dsp_meta dspm = {0};
/* checks */
if (!check_extensions(streamFile, "swd"))
goto fail;
//todo blocked layout when first chunk is 0x50534631 (count + table of 0x0c with offset/sizes)
if (read_32bitBE(0x00,streamFile) != 0x505346d1) /* PSF\0xd1 */
goto fail;
dspm.channel_count = 2;
dspm.max_channels = 2;
dspm.header_offset = 0x08;
dspm.header_spacing = 0x60;
dspm.start_offset = dspm.header_offset + 0x60 * dspm.channel_count;
dspm.interleave = 0x08;
dspm.meta_type = meta_NGC_SWD;
return init_vgmstream_dsp_common(streamFile, &dspm);
fail:
return NULL;
}
/* IDSP - Traveller's Tales header + interleaved dsps [Lego Batman (Wii), Lego Dimensions (Wii U)] */
VGMSTREAM * init_vgmstream_idsp_tt(STREAMFILE *streamFile) {
dsp_meta dspm = {0};
@ -1278,3 +1255,34 @@ VGMSTREAM * init_vgmstream_dsp_ds2(STREAMFILE *streamFile) {
fail:
return NULL;
}
/* .itl - Incinerator Studios interleaved dsp [Cars Race-o-rama (Wii), MX vs ATV Untamed (Wii)] */
VGMSTREAM * init_vgmstream_dsp_itl(STREAMFILE *streamFile) {
dsp_meta dspm = {0};
size_t stream_size;
/* checks */
/* .itl: standard
* .dsp: default to catch a similar file, not sure which devs */
if (!check_extensions(streamFile, "itl,dsp"))
goto fail;
stream_size = get_streamfile_size(streamFile);
dspm.channel_count = 2;
dspm.max_channels = 2;
dspm.start_offset = 0x60;
dspm.interleave = 0x10000;
dspm.interleave_first_skip = dspm.start_offset;
dspm.interleave_first = dspm.interleave - dspm.interleave_first_skip;
dspm.interleave_last = (stream_size / dspm.channel_count) % dspm.interleave;
dspm.header_offset = 0x00;
dspm.header_spacing = dspm.interleave;
//todo some files end in half a frame and may click at the very end
//todo when .dsp should refer to Ultimate Board Collection (Wii), not sure about dev
dspm.meta_type = meta_DSP_ITL_i;
return init_vgmstream_dsp_common(streamFile, &dspm);
fail:
return NULL;
}

View File

@ -108,12 +108,16 @@ static void kovs_ogg_decryption_callback(void *ptr, size_t size, size_t nmemb, v
}
static void psychic_ogg_decryption_callback(void *ptr, size_t size, size_t nmemb, void *datasource) {
ogg_vorbis_streamfile * const ov_streamfile = datasource;
size_t bytes_read = size*nmemb;
uint8_t key[6] = { 0x23,0x31,0x20,0x2e,0x2e,0x28 };
int i;
/* bytes add 0x23 ('#') */ //todo incorrect, add changes every 0x64 bytes
//todo incorrect, picked value changes (fixed order for all files), or key is bigger
/* bytes add key that changes every 0x64 bytes */
for (i = 0; i < bytes_read; i++) {
((uint8_t*)ptr)[i] += 0x23;
int pos = (ov_streamfile->offset + i) / 0x64;
((uint8_t*)ptr)[i] += key[pos % sizeof(key)];
}
}
@ -455,6 +459,7 @@ VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, ov_callb
ogg_vorbis_codec_data * data = NULL;
OggVorbis_File *ovf = NULL;
vorbis_info *vi;
char name[STREAM_NAME_SIZE] = {0};
int loop_flag = ovmi->loop_flag;
int32_t loop_start = ovmi->loop_start;
@ -626,6 +631,10 @@ VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, ov_callb
data->disable_reordering = 1;
}
if (strstr(user_comment, "TITLE=") == user_comment) {
strncpy(name, user_comment + 6, sizeof(name) - 1);
}
;VGM_LOG("OGG: user_comment=%s\n", user_comment);
}
}
@ -638,9 +647,14 @@ VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, ov_callb
vgmstream->codec_data = data; /* store our fun extra datas */
vgmstream->channels = vi->channels;
vgmstream->sample_rate = vi->rate;
vgmstream->num_streams = ovmi->total_subsongs;
vgmstream->stream_size = stream_size;
if (ovmi->total_subsongs) /* not setting it has some effect when showing stream names */
vgmstream->num_streams = ovmi->total_subsongs;
if (name[0] != '\0')
strcpy(vgmstream->stream_name, name);
vgmstream->num_samples = ov_pcm_total(ovf,-1); /* let libvorbisfile find total samples */
if (loop_flag) {
vgmstream->loop_start_sample = loop_start;

View File

@ -1,66 +1,122 @@
#include "meta.h"
#include "../util.h"
#include "../coding/coding.h"
/* VAS (from Pro Baseball Spirits 5) */
/* .VAS - from Konami Jikkyou Powerful Pro Yakyuu games */
VGMSTREAM * init_vgmstream_ps2_vas(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t start_offset;
int loop_flag;
int channel_count;
int loop_flag, channel_count;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("vas",filename_extension(filename))) goto fail;
/* check header */
#if 0
if (read_32bitBE(0x00,streamFile) != 0x00000000) /* 0x0 */
/* checks */
if (!check_extensions(streamFile, "vas"))
goto fail;
if (read_32bitLE(0x00,streamFile) + 0x800 != get_streamfile_size(streamFile))
goto fail;
#endif
loop_flag = (read_32bitLE(0x10,streamFile) != 0);
channel_count = 2;
start_offset = 0x800;
/* header is too simple so test a bit */
if (!ps_check_format(streamFile, start_offset, 0x1000))
goto fail;
/* 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->meta_type = meta_PS2_VAS;
vgmstream->sample_rate = read_32bitLE(0x04,streamFile);
vgmstream->coding_type = coding_PSX;
vgmstream->num_samples = read_32bitLE(0x00,streamFile)*28/16/channel_count;
if (loop_flag) {
vgmstream->loop_start_sample = read_32bitLE(0x14,streamFile)*28/16/channel_count;
vgmstream->loop_end_sample = read_32bitLE(0x00,streamFile)*28/16/channel_count;
}
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x200;
vgmstream->meta_type = meta_PS2_VAS;
/* open the file for reading */
{
int i;
STREAMFILE * file;
file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!file) goto fail;
for (i=0;i<channel_count;i++) {
vgmstream->ch[i].streamfile = file;
vgmstream->ch[i].channel_start_offset=
vgmstream->ch[i].offset=start_offset+
vgmstream->interleave_block_size*i;
}
}
vgmstream->num_samples = ps_bytes_to_samples(read_32bitLE(0x00,streamFile), channel_count);
vgmstream->loop_start_sample = ps_bytes_to_samples(read_32bitLE(0x14,streamFile), channel_count);
vgmstream->loop_end_sample = vgmstream->num_samples;
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
close_vgmstream(vgmstream);
return NULL;
}
/* .VAS in containers */
VGMSTREAM * init_vgmstream_ps2_vas_container(STREAMFILE *streamFile) {
VGMSTREAM *vgmstream = NULL;
STREAMFILE *temp_streamFile = NULL;
off_t subfile_offset = 0;
size_t subfile_size = 0;
int total_subsongs, target_subsong = streamFile->stream_index;
int has_table;
/* checks */
if (!check_extensions(streamFile, "vas"))
goto fail;
if (read_32bitBE(0x00, streamFile) != 0xAB8A5A00) /* fixed value */
goto fail;
if (read_32bitLE(0x04, streamFile)*0x800 + 0x800 != get_streamfile_size(streamFile)) /* just in case */
goto fail;
/* offset table, 0x98 has table size */
has_table = read_32bitLE(0x94, streamFile);
total_subsongs = read_32bitLE(0x08, streamFile); /* also at 0x10 */
if (target_subsong == 0) target_subsong = 1;
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
if (has_table) {
off_t header_offset = 0x800 + 0x10*(target_subsong-1);
/* some values are repeats found in the file sub-header */
subfile_offset = read_32bitLE(header_offset + 0x00,streamFile) * 0x800;
subfile_size = read_32bitLE(header_offset + 0x08,streamFile) + 0x800;
}
else {
/* a bunch of files */
off_t offset = 0x800;
int i;
for (i = 0; i < total_subsongs; i++) {
size_t size = read_32bitLE(offset, streamFile) + 0x800;
if (i + 1 == target_subsong) {
subfile_offset = offset;
subfile_size = size;
break;
}
offset += size;
}
if (i == total_subsongs)
goto fail;
}
temp_streamFile = setup_subfile_streamfile(streamFile, subfile_offset,subfile_size, NULL);
if (!temp_streamFile) goto fail;
vgmstream = init_vgmstream_ps2_vas(temp_streamFile);
if (!vgmstream) goto fail;
vgmstream->num_streams = total_subsongs;
close_streamfile(temp_streamFile);
return vgmstream;
fail:
close_streamfile(temp_streamFile);
close_vgmstream(vgmstream);
return NULL;
}

242
src/meta/psf.c Normal file
View File

@ -0,0 +1,242 @@
#include "meta.h"
#include "../layout/layout.h"
#include "../coding/coding.h"
/* PSF single - Pivotal games single segment (external in some PC/Xbox or inside bigfiles) [The Great Escape, Conflict series] */
VGMSTREAM * init_vgmstream_psf_single(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count, sample_rate, rate_value, interleave;
uint32_t psf_config;
uint8_t flags;
size_t data_size;
coding_t codec;
/* checks */
/* .psf: actual extension
* .swd: bigfile extension */
if (!check_extensions(streamFile, "psf,swd"))
goto fail;
if ((read_32bitBE(0x00,streamFile) & 0xFFFFFF00) != 0x50534600) /* "PSF\00" */
goto fail;
flags = read_8bit(0x03,streamFile);
switch(flags) {
case 0xC0: /* [The Great Escape (PS2), Conflict: Desert Storm (PS2)] */
case 0xA1: /* [Conflict: Desert Storm 2 (PS2)] */
case 0x21: /* [Conflict: Desert Storm 2 (PS2), Conflict: Global Storm (PS2)] */
//case 0x22: /* [Conflict: Vietman (PS2)] */ //todo weird size value, stereo, only one found
channel_count = 2;
if (flags == 0x21)
channel_count = 1;
interleave = 0x10;
codec = coding_PSX;
start_offset = 0x08;
break;
case 0x80: /* [The Great Escape (PC/Xbox), Conflict: Desert Storm (Xbox/GC), Conflict: Desert Storm 2 (Xbox)] */
case 0x81: /* [Conflict: Desert Storm 2 (Xbox), Conflict: Vietnam (Xbox)] */
case 0x01: /* [Conflict: Global Storm (Xbox)] */
channel_count = 2;
if (flags == 0x01)
channel_count = 1;
interleave = 0x10;
codec = coding_PSX_pivotal;
start_offset = 0x08;
break;
case 0xD1: /* [Conflict: Desert Storm 2 (GC)] */
channel_count = 2;
interleave = 0x08;
codec = coding_NGC_DSP;
start_offset = 0x08 + 0x60 * channel_count;
break;
default:
goto fail;
}
loop_flag = 0;
psf_config = read_32bitLE(0x04, streamFile);
/* pitch/cents? */
rate_value = (psf_config >> 20) & 0xFFF;
switch(rate_value) {
//case 0xEB5:
//case 0xEB4:
case 0xEB3: sample_rate = 44100; break;
case 0x555: sample_rate = 16000; break;
case 0x355: sample_rate = 11050; break;
case 0x1d5: sample_rate = 6000; break; /* ? */
case 0x1cc: sample_rate = 5000; break;
default:
VGM_LOG("PSF: unknown rate value %x\n", rate_value);
goto fail;
}
data_size = (psf_config & 0xFFFFF) * (interleave * channel_count); /* in blocks */
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_PSF;
vgmstream->sample_rate = sample_rate;
switch(codec) {
case coding_PSX:
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = interleave;
vgmstream->num_samples = ps_bytes_to_samples(data_size, channel_count);
break;
case coding_PSX_pivotal:
vgmstream->coding_type = coding_PSX_pivotal;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = interleave;
vgmstream->num_samples = ps_cfg_bytes_to_samples(data_size, 0x10, channel_count);
break;
case coding_NGC_DSP:
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = interleave;
/* has standard DSP headers at 0x08 */
dsp_read_coefs_be(vgmstream,streamFile,0x08+0x1c,0x60);
dsp_read_hist_be (vgmstream,streamFile,0x08+0x40,0x60);
vgmstream->num_samples = read_32bitBE(0x08, streamFile);//dsp_bytes_to_samples(data_size, channel_count);
break;
default:
goto fail;
}
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
/* PSF segmented - Pivotal games multiple segments (external in some PC/Xbox or inside bigfiles) [The Great Escape, Conflict series] */
VGMSTREAM * init_vgmstream_psf_segmented(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
STREAMFILE* temp_streamFile = NULL;
segmented_layout_data *data = NULL;
int i, segment_count, loop_flag = 0, loop_start = 0, loop_end = 0;
off_t offset;
/* checks */
/* .psf: actual extension
* .swd: bigfile extension */
if (!check_extensions(streamFile, "psf,swd"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x50534660 && /* "PSF\60" [The Great Escape (PC/Xbox/PS2), Conflict: Desert Storm (Xbox/GC)] */
read_32bitBE(0x00,streamFile) != 0x50534631) /* "PSF\31" [Conflict: Desert Storm 2 (Xbox/GC/PS2)] */
goto fail;
segment_count = read_32bitLE(0x04, streamFile);
loop_flag = 0;
offset = 0x08;
offset += 0x0c; /* first segment points to itself? */
segment_count--;
/* build segments */
data = init_layout_segmented(segment_count);
if (!data) goto fail;
for (i = 0; i < segment_count; i++) {
off_t psf_offset;
size_t psf_size;
uint32_t psf_id;
/* mini table */
psf_offset = read_32bitLE(offset + 0x00, streamFile);
/* 0x04-0c: 0x02*4 transition segments (possibly to 4 song variations) */
/* use last section transition as loop */
if (i + 1 == segment_count) {
loop_flag = 1;
loop_start = read_16bitLE(offset + 0x0a, streamFile) - 1; /* also ignore first segment */
loop_end = i;
}
/* multiple segment can point to the same PSF offset (for repeated song sections) */
//todo reuse repeated VGMSTREAMs to improve memory a bit
psf_id = read_32bitBE(psf_offset + 0x00, streamFile);
psf_size = read_32bitLE(psf_offset + 0x04, streamFile);
if (psf_id == 0x505346D1) //todo improve
psf_size = (psf_size & 0xFFFFF) * 0x10;
else
psf_size = (psf_size & 0xFFFFF) * 0x20;
//;VGM_LOG("PSF: offset=%lx, size=%x\n", psf_offset, psf_size);
temp_streamFile = setup_subfile_streamfile(streamFile, psf_offset, psf_size, "psf");
if (!temp_streamFile) goto fail;
data->segments[i] = init_vgmstream_psf_single(temp_streamFile);
if (!data->segments[i]) goto fail;
offset += 0x0c;
}
/* setup VGMSTREAMs */
if (!setup_layout_segmented(data))
goto fail;
vgmstream = allocate_segmented_vgmstream(data,loop_flag, loop_start, loop_end);
if (!vgmstream) goto fail;
vgmstream->stream_size = get_streamfile_size(streamFile);
return vgmstream;
fail:
if (!vgmstream) free_layout_segmented(data);
close_streamfile(temp_streamFile);
close_vgmstream(vgmstream);
return NULL;
}
#if 0
VGMSTREAM * init_vgmstream_sch(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count;
/* checks */
if (!check_extensions(streamFile, "sch"))
goto fail;
/* chunked format (id+size, GC pads to 0x20 and uses BE/inverted ids):
* - SCH\0: start
* - IMUS: points to a external .psf + segment table (same as in .psf, TGE only?)
* - BANK: volume/etc info? points to something?
* - PFSM: single .psf-like file (larger header)
* - PFST: points to single PSF offset (.psf in TGE, or STREAMS.SWD); may be chained to next PFST?
*
* no other info so total subsongs would be count of usable chunks
* in later games, segmented .psf seems to be removed and PFST is used instead
*/
return vgmstream;
fail:
if (!vgmstream) free_layout_layered(data);
close_streamfile(temp_streamFile);
close_vgmstream(vgmstream);
return NULL;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -67,11 +67,14 @@ VGMSTREAM * init_vgmstream_seg(STREAMFILE *streamFile) {
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x2000;
vgmstream->interleave_first_skip = 0x60;
vgmstream->interleave_first_block_size = vgmstream->interleave_block_size - vgmstream->interleave_first_skip;
/* standard dsp header at start_offset */
dsp_read_coefs_be(vgmstream, streamFile, start_offset+0x1c, vgmstream->interleave_block_size);
dsp_read_hist_be(vgmstream, streamFile, start_offset+0x40, vgmstream->interleave_block_size);
//todo first_interleave: 0x2000 - 60
start_offset += vgmstream->interleave_first_skip;
break;
case 0x70635F00: /* "pc_\0" */

View File

@ -1,118 +1,98 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../layout/layout.h"
#include "../util.h"
/* 3DO format, .str extension and possibly a CTRL header, blocks and
* AIFF-C style format specifier. Blocks are not IFF-compliant. Interesting
* blocks are all SNDS
*/
/* .str - 3DO format with CTRL/SNDS/SHDR blocks [Icebreaker (3DO), Battle Pinball (3DO)] */
VGMSTREAM * init_vgmstream_str_snds(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t start_offset, shdr_offset = -1;
int loop_flag, channel_count, found_shdr = 0;
size_t file_size, ctrl_size = -1;
int channel_count;
int loop_flag = 0;
off_t SHDR_offset = -1;
int FoundSHDR = 0;
int CTRL_size = -1;
size_t file_size;
/* checks */
if (!check_extensions(streamFile, "str"))
goto fail;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("str",filename_extension(filename))) goto fail;
/* check for opening CTRL or SNDS chunk */
if (read_32bitBE(0x0,streamFile) != 0x4354524c && /* CTRL */
read_32bitBE(0x0,streamFile) != 0x534e4453 && // SNDS
read_32bitBE(0x0,streamFile) != 0x53484452) // SHDR
if (read_32bitBE(0x00,streamFile) != 0x4354524c && /* "CTRL" */
read_32bitBE(0x00,streamFile) != 0x534e4453 && /* "SNDS" */
read_32bitBE(0x00,streamFile) != 0x53484452) /* "SHDR" */
goto fail;
file_size = get_streamfile_size(streamFile);
start_offset = 0x00;
/* scan chunks until we find a SNDS containing a SHDR */
{
off_t current_chunk;
off_t current_chunk = 0;
current_chunk = 0;
while (!FoundSHDR && current_chunk < file_size) {
while (!found_shdr && current_chunk < file_size) {
if (current_chunk < 0) goto fail;
if (current_chunk+read_32bitBE(current_chunk+4,streamFile) >=
file_size) goto fail;
if (current_chunk+read_32bitBE(current_chunk+0x04,streamFile) >= file_size)
goto fail;
switch (read_32bitBE(current_chunk,streamFile))
{
case 0x4354524C: /* CTRL */
switch (read_32bitBE(current_chunk,streamFile)) {
case 0x4354524C: /* "CTRL" */
ctrl_size = read_32bitBE(current_chunk+4,streamFile);
break;
case 0x534e4453: /* "SNDS" */
switch (read_32bitBE(current_chunk+16,streamFile)) {
case 0x53484452: /* SHDR */
found_shdr = 1;
shdr_offset = current_chunk+16;
break;
default:
break;
}
break;
case 0x53484452: /* "SHDR" */
switch (read_32bitBE(current_chunk+0x7C, streamFile)) {
case 0x4354524C: /* "CTRL" */
/* to distinguish between styles */
CTRL_size = read_32bitBE(current_chunk+4,streamFile);
break;
case 0x534e4453: /* SNDS */
switch (read_32bitBE(current_chunk+16,streamFile))
{
case 0x53484452: /* SHDR */
FoundSHDR = 1;
SHDR_offset = current_chunk+16;
ctrl_size = read_32bitBE(current_chunk + 0x80, streamFile);
break;
default:
break;
}
break;
case 0x53484452: /* SHDR */
switch (read_32bitBE(current_chunk+0x7C, streamFile))
{
case 0x4354524C: /* CTRL */
// to distinguish between styles
CTRL_size = read_32bitBE(current_chunk + 0x80, streamFile);
break;
default:
break;
}
break;
default:
/* ignore others for now */
break;
}
current_chunk += read_32bitBE(current_chunk+4,streamFile);
current_chunk += read_32bitBE(current_chunk+0x04,streamFile);
}
}
if (!FoundSHDR) goto fail;
if (!found_shdr) goto fail;
/* details */
channel_count = read_32bitBE(SHDR_offset+0x20,streamFile);
channel_count = read_32bitBE(shdr_offset+0x20,streamFile);
loop_flag = 0;
/* build the VGMSTREAM */
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
if ((CTRL_size == 0x1C) ||
(CTRL_size == 0x0B) ||
(CTRL_size == -1))
{
vgmstream->num_samples =
read_32bitBE(SHDR_offset+0x2c,streamFile)-1; /* sample count? */
vgmstream->meta_type = meta_STR_SNDS;
vgmstream->sample_rate = read_32bitBE(shdr_offset+0x1c,streamFile);
if (ctrl_size == 0x1C || ctrl_size == 0x0B || ctrl_size == -1) {
vgmstream->num_samples = read_32bitBE(shdr_offset+0x2c,streamFile) - 1; /* sample count? */
}
else {
vgmstream->num_samples =
read_32bitBE(SHDR_offset+0x2c,streamFile) /* frame count? */
* 0x10;
vgmstream->num_samples = read_32bitBE(shdr_offset+0x2c,streamFile) * 0x10; /* frame count? */
}
vgmstream->num_samples /= vgmstream->channels;
vgmstream->sample_rate = read_32bitBE(SHDR_offset+0x1c,streamFile);
switch (read_32bitBE(SHDR_offset+0x24,streamFile)) {
case 0x53445832: /* SDX2 */
switch (read_32bitBE(shdr_offset+0x24,streamFile)) {
case 0x53445832: /* "SDX2" */
if (channel_count > 1) {
vgmstream->coding_type = coding_SDX2_int;
vgmstream->interleave_block_size = 1;
@ -123,33 +103,12 @@ VGMSTREAM * init_vgmstream_str_snds(STREAMFILE *streamFile) {
goto fail;
}
vgmstream->layout_type = layout_blocked_str_snds;
vgmstream->meta_type = meta_STR_SNDS;
/* channels and loop flag are set by allocate_vgmstream */
if (loop_flag) {
/* just guessin', no way to set loop flag anyway */
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = vgmstream->num_samples;
}
/* open the file for reading by each channel */
{
int i;
vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,
STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!vgmstream->ch[0].streamfile) goto fail;
for (i=0;i<channel_count;i++) {
vgmstream->ch[i].streamfile = vgmstream->ch[0].streamfile;
}
}
/* start me up */
block_update_str_snds(0,vgmstream);
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -6,7 +6,7 @@
VGMSTREAM * init_vgmstream_vag(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
size_t file_size, channel_size, interleave;
size_t file_size, channel_size, interleave, interleave_first = 0, interleave_first_skip = 0;
meta_t meta_type;
int channel_count = 0, loop_flag, sample_rate;
uint32_t vag_id, version;
@ -80,7 +80,7 @@ VGMSTREAM * init_vgmstream_vag(STREAMFILE *streamFile) {
case 0x70474156: /* pGAV (little endian / stereo) [Jak 3 (PS2), Jak X (PS2)] */
meta_type = meta_PS2_pGAV;
start_offset = 0x00; //todo 0x30, requires interleave_first
start_offset = 0x30;
if (read_32bitBE(0x20,streamFile) == 0x53746572) { /* "Ster" */
channel_count = 2;
@ -91,7 +91,8 @@ VGMSTREAM * init_vgmstream_vag(STREAMFILE *streamFile) {
interleave = 0x1000; /* Jak X interleave, includes header */
else
interleave = 0x2000; /* Jak 3 interleave in rare files, no header */
//todo interleave_first = interleave - start_offset; /* interleave includes header */
interleave_first = interleave - start_offset; /* interleave includes header */
interleave_first_skip = start_offset;
}
else {
channel_count = 1;
@ -127,21 +128,21 @@ VGMSTREAM * init_vgmstream_vag(STREAMFILE *streamFile) {
}
else if (read_32bitBE(0x6000,streamFile) == 0x56414770) { /* "VAGp" */
/* The Simpsons Wrestling (PS1) */
start_offset = 0x00; //todo 0x30, requires interleave_first
start_offset = 0x30;
channel_count = 2;
interleave = 0x6000;
//todo interleave_first = interleave - start_offset; /* includes header */
channel_size += 0x30;
interleave_first = interleave - start_offset; /* includes header */
interleave_first_skip = start_offset;
loop_flag = 0;
}
else if (read_32bitBE(0x1000,streamFile) == 0x56414770) { /* "VAGp" */
/* Shikigami no Shiro (PS2) */
start_offset = 0x00; //todo 0x30, requires interleave_first
start_offset = 0x30;
channel_count = 2;
interleave = 0x1000;
//todo interleave_first = interleave - start_offset; /* includes header */
channel_size += 0x30;
interleave_first = interleave - start_offset; /* includes header */
interleave_first_skip = start_offset;
loop_flag = ps_find_loop_offsets(streamFile, start_offset, channel_size*channel_count, channel_count, interleave, &loop_start_sample, &loop_end_sample);
}
@ -244,6 +245,9 @@ VGMSTREAM * init_vgmstream_vag(STREAMFILE *streamFile) {
vgmstream->coding_type = coding_HEVAG;
vgmstream->layout_type = (channel_count == 1) ? layout_none : layout_interleave;
vgmstream->interleave_block_size = interleave;
vgmstream->interleave_first_block_size = interleave_first;
vgmstream->interleave_first_skip = interleave_first_skip;
read_string(vgmstream->stream_name,0x10+1, 0x20,streamFile); /* always, can be null */

View File

@ -221,6 +221,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
goto fail;
}
start_offset = ww.data_offset;
/* build the VGMSTREAM */
@ -303,7 +304,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
cfg.setup_type = WWV_EXTERNAL_CODEBOOKS; /* setup_type will be corrected later */
break;
case 0x2a: /* uncommon (mid 2011) [inFamous 2 (PS3)] */
case 0x2a: /* uncommon (mid 2011) [inFamous 2 (PS3), Captain America: Super Soldier (X360)] */
data_offsets = 0x10;
block_offsets = 0x28;
cfg.header_type = WWV_TYPE_2;
@ -325,6 +326,14 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
}
ww.data_size -= audio_offset;
/* detect normal packets */
if (vorb_size == 0x2a) {
/* almost all blocksizes are 0x08+0x0B except a few with 0x0a+0x0a [Captain America: Super Soldier (X360) voices/sfx] */
if (cfg.blocksize_0_exp == cfg.blocksize_1_exp)
cfg.packet_type = WWV_STANDARD;
}
/* detect setup type:
* - full inline: ~2009, ex. The King of Fighters XII (X360), The Saboteur (PC)
* - trimmed inline: ~2010, ex. Army of Two: 40 days (X360) some multiplayer files
@ -378,11 +387,9 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
cfg.blocksize_0_exp = read_8bit(extra_offset + block_offsets + 0x01, streamFile); /* big */
ww.data_size -= audio_offset;
/* Normal packets are used rarely (ex. Oddworld New 'n' Tasty! (PSV)). They are hard to detect (decoding
* will mostly work with garbage results) but we'll try. Setup size and "fmt" bitrate fields may matter too. */
/* detect normal packets */
if (ww.extra_size == 0x30) {
/* all blocksizes I've seen are 0x08+0x0B except Oddworld (PSV), that uses 0x09+0x09
* (maybe lower spec machines = needs simpler packets) */
/* almost all blocksizes are 0x08+0x0B except some with 0x09+0x09 [Oddworld New 'n' Tasty! (PSV)] */
if (cfg.blocksize_0_exp == cfg.blocksize_1_exp)
cfg.packet_type = WWV_STANDARD;
}
@ -438,6 +445,15 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
goto fail;
}
/* for some reason all(?) DSP .wem do full loops (even mono/jingles/etc) but
* several tracks do loop like this, so disable it for short-ish tracks */
if (ww.loop_flag && vgmstream->loop_start_sample == 0 &&
vgmstream->loop_end_sample < 20*ww.sample_rate) { /* in seconds */
vgmstream->loop_flag = 0;
}
/* get coefs and default history */
dsp_read_coefs(vgmstream,streamFile,wiih_offset, 0x2e, ww.big_endian);
for (i=0; i < ww.channels; i++) {

View File

@ -635,10 +635,11 @@ static int get_xsb_name(char * buf, size_t maxsize, int target_subsong, xwb_head
}
//;VGM_LOG("XSB: name found=%i at %lx\n", xsb.parse_found, xsb.name_offset);
if (!xsb.parse_found || xsb.name_offset == 0)
if (!xsb.name_len || xsb.name[0] == '\0')
goto fail;
read_string(buf,maxsize, xsb.name_offset,streamFile); /* null-terminated */
strncpy(buf,xsb.name,maxsize);
buf[maxsize-1] = '\0';
return 1;
fail:
return 0;

View File

@ -1,5 +1,6 @@
#ifndef _XWB_XSB_H_
#define _XWB_XSB_H_
#include "meta.h"
#define XSB_XACT1_0_MAX 5 /* Unreal Championship (Xbox) */
#define XSB_XACT1_1_MAX 8 /* Die Hard: Vendetta (Xbox) */
@ -30,9 +31,9 @@ typedef struct {
off_t cue_names_offset;
/* output */
int parse_found;
int parse_done;
off_t name_offset;
char name[STREAM_NAME_SIZE];
int name_len;
} xsb_header;
@ -41,24 +42,30 @@ static void xsb_check_stream(xsb_header * xsb, int stream_index, int wavebank_in
if (xsb->parse_done)
return;
/* multiple names may correspond to a stream, so commenting parse_done
* will allow to search for other names instead of first only */
/* multiple names may correspond to a stream (ex. Blue Dragon), so we concat all */
if (xsb->selected_stream == stream_index &&
(xsb->selected_wavebank == wavebank_index || wavebank_index == -1 || wavebank_index == 255)) {
xsb->name_offset = name_offset;
xsb->parse_found = 1;
xsb->parse_done = 1;
char name[STREAM_NAME_SIZE];
size_t name_size;
name_size = read_string(name,sizeof(name), name_offset,sf); /* null-terminated */
if (xsb->name_len) {
const char *cat = "; ";
int cat_len = 2;
if (xsb->name_len + cat_len + name_size + 1 < STREAM_NAME_SIZE) {
strcat(xsb->name + xsb->name_len, cat);
strcat(xsb->name + xsb->name_len, name);
}
}
else {
strcpy(xsb->name, name);
}
xsb->name_len += name_size;
//xsb->parse_done = 1; /* uncomment this to stop reading after first name */
//;VGM_LOG("XSB: parse found stream=%i, wavebank=%i, name_offset=%lx\n", stream_index, wavebank_index, name_offset);
}
#if 0 // for debugging purposes
{
char stream_name[255];
read_string(stream_name,255, name_offset,sf); /* null-terminated */
;VGM_LOG("XSB: stream=%i, wavebank=%i, name=%lx=%s vs s=%i, w=%i\n", stream_index, wavebank_index, name_offset, stream_name, xsb->selected_stream, xsb->selected_wavebank);
xsb->parse_done = 0; /* keep parsing */
}
#endif
}
/* old XACT1 is a bit different and much of it is unknown but this seems to work.

View File

@ -118,12 +118,12 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_ps2_pcm,
init_vgmstream_ps2_rkv,
init_vgmstream_ps2_vas,
init_vgmstream_ps2_vas_container,
init_vgmstream_ps2_tec,
init_vgmstream_ps2_enth,
init_vgmstream_sdt,
init_vgmstream_aix,
init_vgmstream_ngc_tydsp,
init_vgmstream_ngc_swd,
init_vgmstream_capdsp,
init_vgmstream_xbox_wvs,
init_vgmstream_ngc_wvs,
@ -157,21 +157,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_wii_mus,
init_vgmstream_dc_asd,
init_vgmstream_naomi_spsd,
init_vgmstream_rsd2vag,
init_vgmstream_rsd2pcmb,
init_vgmstream_rsd2xadp,
init_vgmstream_rsd3vag,
init_vgmstream_rsd3gadp,
init_vgmstream_rsd3pcm,
init_vgmstream_rsd3pcmb,
init_vgmstream_rsd4pcmb,
init_vgmstream_rsd4pcm,
init_vgmstream_rsd4radp,
init_vgmstream_rsd4vag,
init_vgmstream_rsd6vag,
init_vgmstream_rsd6wadp,
init_vgmstream_rsd6xadp,
init_vgmstream_rsd6radp,
init_vgmstream_rsd,
init_vgmstream_bgw,
init_vgmstream_spw,
init_vgmstream_ps2_ass,
@ -305,7 +291,6 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_ps3_ivag,
init_vgmstream_ps2_2pfs,
init_vgmstream_xnb,
init_vgmstream_rsd6oogv,
init_vgmstream_ubi_ckd,
init_vgmstream_ps2_vbk,
init_vgmstream_otm,
@ -335,7 +320,6 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_ogl,
init_vgmstream_mc3,
init_vgmstream_gtd,
init_vgmstream_rsd6xma,
init_vgmstream_ta_aac_x360,
init_vgmstream_ta_aac_ps3,
init_vgmstream_ta_aac_mobile,
@ -395,8 +379,6 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_waf,
init_vgmstream_wave,
init_vgmstream_wave_segmented,
init_vgmstream_rsd6at3p,
init_vgmstream_rsd6wma,
init_vgmstream_smv,
init_vgmstream_nxap,
init_vgmstream_ea_wve_au00,
@ -486,6 +468,9 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_smk,
init_vgmstream_mzrt,
init_vgmstream_xavs,
init_vgmstream_psf_single,
init_vgmstream_psf_segmented,
init_vgmstream_dsp_itl,
/* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */
init_vgmstream_txth, /* proper parsers should supersede TXTH, once added */
@ -1190,7 +1175,8 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
case coding_HEVAG:
return 28;
case coding_PSX_cfg:
return (vgmstream->interleave_block_size - 1) * 2; /* decodes 1 byte into 2 bytes */
case coding_PSX_pivotal:
return (vgmstream->interleave_block_size - 0x01) * 2; /* size 0x01 header */
case coding_EA_XA:
case coding_EA_XA_int:
@ -1378,6 +1364,7 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
case coding_HEVAG:
return 0x10;
case coding_PSX_cfg:
case coding_PSX_pivotal:
return vgmstream->interleave_block_size;
case coding_EA_XA:
@ -1693,6 +1680,13 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
vgmstream->channels,vgmstream->samples_into_block,samples_to_do, vgmstream->interleave_block_size);
}
break;
case coding_PSX_pivotal:
for (ch = 0; ch < vgmstream->channels; ch++) {
decode_psx_pivotal(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch,
vgmstream->channels,vgmstream->samples_into_block,samples_to_do,
vgmstream->interleave_block_size);
}
break;
case coding_HEVAG:
for (ch = 0; ch < vgmstream->channels; ch++) {
decode_hevag(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch,
@ -2429,6 +2423,11 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
snprintf(temp,TEMPSIZE, "interleave: %#x bytes\n", (int32_t)vgmstream->interleave_block_size);
concatn(length,desc,temp);
if (vgmstream->interleave_first_block_size) {
snprintf(temp,TEMPSIZE, "interleave first block: %#x bytes\n", (int32_t)vgmstream->interleave_first_block_size);
concatn(length,desc,temp);
}
if (vgmstream->interleave_last_block_size) {
snprintf(temp,TEMPSIZE, "interleave last block: %#x bytes\n", (int32_t)vgmstream->interleave_last_block_size);
concatn(length,desc,temp);
@ -2824,6 +2823,12 @@ int vgmstream_open_stream(VGMSTREAM * vgmstream, STREAMFILE *streamFile, off_t s
vgmstream->coding_type == coding_CRI_HCA)
return 1;
#ifdef VGM_USE_VORBIS
/* stream/offsets not needed, managed by decoder */
if (vgmstream->coding_type == coding_OGG_VORBIS)
return 1;
#endif
#ifdef VGM_USE_FFMPEG
/* stream/offsets not needed, managed by decoder */
if (vgmstream->coding_type == coding_FFmpeg)

View File

@ -104,7 +104,8 @@ typedef enum {
coding_XA, /* CD-ROM XA */
coding_PSX, /* Sony PS ADPCM (VAG) */
coding_PSX_badflags, /* Sony PS ADPCM with custom flag byte */
coding_PSX_cfg, /* Sony PS ADPCM with configurable frame size (FF XI, SGXD type 5, Bizarre Creations) */
coding_PSX_cfg, /* Sony PS ADPCM with configurable frame size (int math) */
coding_PSX_pivotal, /* Sony PS ADPCM with configurable frame size (float math) */
coding_HEVAG, /* Sony PSVita ADPCM */
coding_EA_XA, /* Electronic Arts EA-XA ADPCM v1 (stereo) aka "EA ADPCM" */
@ -389,7 +390,6 @@ typedef enum {
meta_PS2_ENTH, /* Enthusia */
meta_SDT, /* Baldur's Gate - Dark Alliance */
meta_NGC_TYDSP, /* Ty - The Tasmanian Tiger */
meta_NGC_SWD, /* Conflict - Desert Storm 1 & 2 */
meta_CAPDSP, /* Capcom DSP Header [no header_id] */
meta_DC_STR, /* SEGA Stream Asset Builder */
meta_DC_STR_V2, /* variant of SEGA Stream Asset Builder */
@ -420,27 +420,7 @@ typedef enum {
meta_NGC_PDT, /* Mario Party 6 */
meta_DC_ASD, /* Miss Moonligh */
meta_NAOMI_SPSD, /* Guilty Gear X */
meta_RSD2VAG, /* RSD2VAG */
meta_RSD2PCMB, /* RSD2PCMB */
meta_RSD2XADP, /* RSD2XADP */
meta_RSD3VAG, /* RSD3VAG */
meta_RSD3GADP, /* RSD3GADP */
meta_RSD3PCM, /* RSD3PCM */
meta_RSD3PCMB, /* RSD3PCMB */
meta_RSD4PCMB, /* RSD4PCMB */
meta_RSD4PCM, /* RSD4PCM */
meta_RSD4RADP, /* RSD4RADP */
meta_RSD4VAG, /* RSD4VAG */
meta_RSD6VAG, /* RSD6VAG */
meta_RSD6WADP, /* RSD6WADP */
meta_RSD6XADP, /* RSD6XADP */
meta_RSD6RADP, /* RSD6RADP */
meta_RSD6OOGV, /* RSD6OOGV */
meta_RSD6XMA, /* RSD6XMA */
meta_RSD6AT3P, /* RSD6AT3+ */
meta_RSD6WMA, /* RSD6WMA */
meta_RSD,
meta_PS2_ASS, /* ASS */
meta_SEG, /* Eragon */
meta_NDS_STRM_FFTA2, /* Final Fantasy Tactics A2 */
@ -732,6 +712,8 @@ typedef enum {
meta_SMACKER,
meta_MZRT,
meta_XAVS,
meta_PSF,
meta_DSP_ITL_i,
} meta_t;
@ -843,6 +825,8 @@ typedef struct {
/* layouts/block config */
size_t interleave_block_size; /* interleave, or block/frame size (depending on the codec) */
size_t interleave_first_block_size; /* different interleave for first block */
size_t interleave_first_skip; /* data skipped before interleave first (needed to skip other channels) */
size_t interleave_last_block_size; /* smaller interleave for last block */
/* subsong config */