Updated VGMStream to r1050-532-gba4e6d1f.
parent
d2dc14a72c
commit
5df7a8f5c6
|
@ -245,7 +245,7 @@
|
|||
836F6FF118BDC2190095E648 /* ps2_psw.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EB518BDC2180095E648 /* ps2_psw.c */; };
|
||||
836F6FF218BDC2190095E648 /* ps2_rnd.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EB618BDC2180095E648 /* ps2_rnd.c */; };
|
||||
836F6FF318BDC2190095E648 /* ps2_rstm.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EB718BDC2180095E648 /* ps2_rstm.c */; };
|
||||
836F6FF418BDC2190095E648 /* ps2_rws.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EB818BDC2180095E648 /* ps2_rws.c */; };
|
||||
836F6FF418BDC2190095E648 /* rws.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EB818BDC2180095E648 /* rws.c */; };
|
||||
836F6FF618BDC2190095E648 /* ps2_sfs.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EBA18BDC2180095E648 /* ps2_sfs.c */; };
|
||||
836F6FF718BDC2190095E648 /* ps2_sl3.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EBB18BDC2180095E648 /* ps2_sl3.c */; };
|
||||
836F6FF818BDC2190095E648 /* ps2_smpl.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EBC18BDC2180095E648 /* ps2_smpl.c */; };
|
||||
|
@ -725,7 +725,7 @@
|
|||
836F6EB518BDC2180095E648 /* ps2_psw.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_psw.c; sourceTree = "<group>"; };
|
||||
836F6EB618BDC2180095E648 /* ps2_rnd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_rnd.c; sourceTree = "<group>"; };
|
||||
836F6EB718BDC2180095E648 /* ps2_rstm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_rstm.c; sourceTree = "<group>"; };
|
||||
836F6EB818BDC2180095E648 /* ps2_rws.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_rws.c; sourceTree = "<group>"; };
|
||||
836F6EB818BDC2180095E648 /* rws.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rws.c; sourceTree = "<group>"; };
|
||||
836F6EBA18BDC2180095E648 /* ps2_sfs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_sfs.c; sourceTree = "<group>"; };
|
||||
836F6EBB18BDC2180095E648 /* ps2_sl3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_sl3.c; sourceTree = "<group>"; };
|
||||
836F6EBC18BDC2180095E648 /* ps2_smpl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_smpl.c; sourceTree = "<group>"; };
|
||||
|
@ -1264,7 +1264,7 @@
|
|||
836F6EB518BDC2180095E648 /* ps2_psw.c */,
|
||||
836F6EB618BDC2180095E648 /* ps2_rnd.c */,
|
||||
836F6EB718BDC2180095E648 /* ps2_rstm.c */,
|
||||
836F6EB818BDC2180095E648 /* ps2_rws.c */,
|
||||
836F6EB818BDC2180095E648 /* rws.c */,
|
||||
836F6EBA18BDC2180095E648 /* ps2_sfs.c */,
|
||||
836F6EBB18BDC2180095E648 /* ps2_sl3.c */,
|
||||
836F6EBC18BDC2180095E648 /* ps2_smpl.c */,
|
||||
|
@ -1811,7 +1811,7 @@
|
|||
83709E051ECBC1A4005C03D3 /* gtd.c in Sources */,
|
||||
836F704A18BDC2190095E648 /* xbox_wavm.c in Sources */,
|
||||
836F6F8618BDC2190095E648 /* excitebots.c in Sources */,
|
||||
836F6FF418BDC2190095E648 /* ps2_rws.c in Sources */,
|
||||
836F6FF418BDC2190095E648 /* rws.c in Sources */,
|
||||
836F6F2518BDC2190095E648 /* g721_decoder.c in Sources */,
|
||||
836F6FE818BDC2190095E648 /* ps2_mic.c in Sources */,
|
||||
836F6F3C18BDC2190095E648 /* xa_decoder.c in Sources */,
|
||||
|
|
|
@ -57,6 +57,7 @@ void decode_pcm8_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspac
|
|||
void decode_pcm8_sb_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_pcm8_unsigned_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_pcm8_unsigned(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_ulaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
size_t pcm_bytes_to_samples(size_t bytes, int channels, int bits_per_sample);
|
||||
|
||||
/* psx_decoder */
|
||||
|
|
|
@ -97,11 +97,12 @@ static void mta2_block_update(VGMSTREAMCHANNEL * stream) {
|
|||
void decode_mta2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
int samples_done = 0, sample_count = 0, channel_block_samples, channel_first_sample, frame_size = 0;
|
||||
int i, group, row, col;
|
||||
int num_track = 0, channel_layout, track_channels = 0, track_channel;
|
||||
int track_channels = 0, track_channel;
|
||||
|
||||
|
||||
/* block/track skip */
|
||||
do {
|
||||
int num_track = 0, channel_layout;
|
||||
/* autodetect and skip macroblock header */
|
||||
mta2_block_update(stream);
|
||||
|
||||
|
@ -112,8 +113,13 @@ void decode_mta2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
|
|||
frame_size = read_16bitBE(stream->offset+0x06,stream->streamfile); /* not including this header */
|
||||
/* 0x08(8): null */
|
||||
|
||||
if (num_track < 0)
|
||||
break; /* EOF: whatever */
|
||||
/* EOF: 0-fill buffer (or, as track_channels = 0 > divs by 0) */
|
||||
if (num_track < 0) {
|
||||
for (i = 0; i < samples_to_do; i++)
|
||||
outbuf[i * channelspacing] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
track_channels = 0;
|
||||
for (i = 0; i < 8; i++) {
|
||||
|
|
|
@ -86,6 +86,38 @@ void decode_pcm16LE_XOR_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int chan
|
|||
}
|
||||
}
|
||||
|
||||
/* decodes u-law (ITU G.711 non-linear PCM) */
|
||||
void decode_ulaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i;
|
||||
int32_t sample_count;
|
||||
int sign, segment, quantization, sample;
|
||||
const int bias = 0x84;
|
||||
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
uint8_t ulawbyte = read_8bit(stream->offset+i,stream->streamfile);
|
||||
|
||||
ulawbyte = ~ulawbyte; /* stored in complement */
|
||||
sign = (ulawbyte & 0x80);
|
||||
segment = (ulawbyte & 0x70) >> 4; /* exponent */
|
||||
quantization = ulawbyte & 0x0F; /* mantissa */
|
||||
|
||||
sample = (quantization << 3) + bias; /* add bias */
|
||||
sample <<= segment;
|
||||
sample = (sign) ? (bias - sample) : (sample - bias); /* remove bias */
|
||||
|
||||
#if 0 // the above follows Sun's implementation, but this works too
|
||||
{
|
||||
static int exp_lut[8] = {0,132,396,924,1980,4092,8316,16764}; /* precalcs from bias */
|
||||
sample = exp_lut[segment] + (quantization << (segment + 3));
|
||||
if (sign != 0) sample = -sample;
|
||||
}
|
||||
#endif
|
||||
|
||||
outbuf[sample_count] = sample;
|
||||
}
|
||||
}
|
||||
|
||||
size_t pcm_bytes_to_samples(size_t bytes, int channels, int bits_per_sample) {
|
||||
return bytes / channels / (bits_per_sample/8);
|
||||
}
|
||||
|
|
|
@ -283,6 +283,7 @@ static const char* extension_list[] = {
|
|||
"tun",
|
||||
"tydsp",
|
||||
|
||||
"ulw",
|
||||
"um3",
|
||||
|
||||
"vag",
|
||||
|
@ -394,6 +395,7 @@ static const coding_info coding_info_list[] = {
|
|||
{coding_PCM8_U_int, "8-bit unsigned PCM with 1 byte interleave"},
|
||||
{coding_PCM8_int, "8-bit PCM with 1 byte interleave"},
|
||||
{coding_PCM8_SB_int, "8-bit PCM with sign bit, 1 byte interleave"},
|
||||
{coding_ULAW, "8-bit u-Law"},
|
||||
{coding_CRI_ADX, "CRI ADX 4-bit ADPCM"},
|
||||
{coding_CRI_ADX_exp, "CRI ADX 4-bit ADPCM with exponential scale"},
|
||||
{coding_CRI_ADX_fixed, "CRI ADX 4-bit ADPCM with fixed coefficients"},
|
||||
|
@ -515,6 +517,7 @@ static const layout_info layout_info_list[] = {
|
|||
{layout_ivaud_blocked, "GTA IV blocked"},
|
||||
{layout_ps2_iab_blocked, "IAB blocked"},
|
||||
{layout_ps2_strlr_blocked, "The Bouncer STR blocked"},
|
||||
{layout_rws_blocked, "RWS blocked"},
|
||||
{layout_tra_blocked, "TRA blocked"},
|
||||
{layout_acm, "ACM blocked"},
|
||||
{layout_mus_acm, "multiple ACM files, ACM blocked"},
|
||||
|
@ -614,7 +617,7 @@ static const meta_info meta_info_list[] = {
|
|||
{meta_XSS, "Dino Crisis 3 XSS File"},
|
||||
{meta_HGC1, "Knights of the Temple 2 hgC1 Header"},
|
||||
{meta_AUS, "Capcom AUS Header"},
|
||||
{meta_RWS, "RWS Header"},
|
||||
{meta_RWS, "RenderWare RWS header"},
|
||||
{meta_EACS_PC, "EACS Header (PC)"},
|
||||
{meta_EACS_PSX, "EACS Header (PSX)"},
|
||||
{meta_EACS_SAT, "EACS Header (SATURN)"},
|
||||
|
@ -866,6 +869,7 @@ static const meta_info meta_info_list[] = {
|
|||
{meta_TA_AAC_X360, "tri-Ace AAC (X360) header"},
|
||||
{meta_TA_AAC_PS3, "tri-Ace AAC (PS3) header"},
|
||||
{meta_PS3_MTA2, "Konami MTA2 header"},
|
||||
{meta_NGC_ULW, "Criterion ULW raw header"},
|
||||
|
||||
#ifdef VGM_USE_VORBIS
|
||||
{meta_OGG_VORBIS, "Ogg Vorbis"},
|
||||
|
|
|
@ -129,6 +129,9 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM *
|
|||
break;
|
||||
case layout_ps2_strlr_blocked:
|
||||
ps2_strlr_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_rws_blocked:
|
||||
rws_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -59,6 +59,8 @@ void ps2_iab_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
|||
|
||||
void ps2_strlr_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void rws_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
/* other layouts */
|
||||
void render_vgmstream_interleave(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
|
||||
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* a simple headerless block with padding; configured in the main header */
|
||||
void rws_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i;
|
||||
size_t block_size;
|
||||
size_t interleave;
|
||||
|
||||
/* no header; size is configured in the main header */
|
||||
block_size = vgmstream->full_block_size;
|
||||
interleave = vgmstream->interleave_block_size;
|
||||
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->next_block_offset = block_offset
|
||||
+ block_size;
|
||||
|
||||
for (i=0;i<vgmstream->channels;i++) {
|
||||
vgmstream->ch[i].offset = block_offset + interleave*i;
|
||||
}
|
||||
}
|
|
@ -672,4 +672,6 @@ VGMSTREAM * init_vgmstream_ta_aac_ps3(STREAMFILE *streamFile);
|
|||
|
||||
VGMSTREAM * init_vgmstream_ps3_mta2(STREAMFILE *streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ngc_ulw(STREAMFILE * streamFile);
|
||||
|
||||
#endif /*_META_H*/
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* ULW - headerless U-law, found in Burnout (GC) */
|
||||
VGMSTREAM * init_vgmstream_ngc_ulw(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag = 0, channel_count;
|
||||
|
||||
|
||||
/* check extension, case insensitive */
|
||||
if ( !check_extensions(streamFile,"ulw"))
|
||||
goto fail;
|
||||
|
||||
/* raw data, the info is in the filename (really!) */
|
||||
{
|
||||
char* path;
|
||||
char basename[PATH_LIMIT];
|
||||
char filename[PATH_LIMIT];
|
||||
|
||||
/* get base name */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
path = strrchr(filename,DIR_SEPARATOR);
|
||||
if (path!=NULL)
|
||||
path = path+1;
|
||||
else
|
||||
path = filename;
|
||||
strcpy(basename,path);
|
||||
|
||||
/* first letter gives the channels */
|
||||
if (basename[0]=='M') /* Mono */
|
||||
channel_count = 1;
|
||||
else if (basename[0]=='S' || basename[0]=='D') /* Stereo/Dolby */
|
||||
channel_count = 2;
|
||||
else
|
||||
goto fail;
|
||||
|
||||
/* not very robust but meh (other tracks don't loop) */
|
||||
if (strcmp(basename,"MMenu.ulw")==0 || strcmp(basename,"DMenu.ulw")==0) {
|
||||
loop_flag = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = 32000;
|
||||
vgmstream->coding_type = coding_ULAW;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x01;
|
||||
vgmstream->meta_type = meta_NGC_ULW;
|
||||
vgmstream->num_samples = pcm_bytes_to_samples(get_streamfile_size(streamFile), channel_count, 8);
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
}
|
||||
|
||||
start_offset = 0;
|
||||
|
||||
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
|
@ -1,103 +0,0 @@
|
|||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* RWS (Silent Hill Origins, Ghost Rider, Max Payne 2) */
|
||||
VGMSTREAM * init_vgmstream_rws(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
off_t start_offset;
|
||||
|
||||
int loop_flag = 0;
|
||||
int channel_count;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("rws",filename_extension(filename))) goto fail;
|
||||
|
||||
/* check header */
|
||||
if (read_32bitBE(0x00,streamFile) != 0x0D080000)
|
||||
goto fail;
|
||||
#if 0
|
||||
/* check if is used as container file */
|
||||
if (read_32bitBE(0x38,streamFile) != 0x01000000)
|
||||
goto fail;
|
||||
#endif
|
||||
|
||||
loop_flag = 1;
|
||||
channel_count = 2;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
start_offset = read_32bitLE(0x50,streamFile);
|
||||
vgmstream->channels = channel_count;
|
||||
|
||||
|
||||
switch (read_32bitLE(0x38,streamFile)) {
|
||||
case 0x01:
|
||||
vgmstream->sample_rate = read_32bitLE(0xE4,streamFile);
|
||||
vgmstream->num_samples = read_32bitLE(0x98,streamFile)/16*28/vgmstream->channels;
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = read_32bitLE(0x98,streamFile)/16*28/vgmstream->channels;
|
||||
}
|
||||
break;
|
||||
case 0x02:
|
||||
if (start_offset < 0x800) // Max Payne 2
|
||||
{
|
||||
vgmstream->sample_rate = read_32bitLE(0x178,streamFile);
|
||||
vgmstream->num_samples = read_32bitLE(0x150,streamFile)/16*28/vgmstream->channels;
|
||||
if (loop_flag)
|
||||
{
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = read_32bitLE(0x150,streamFile)/16*28/vgmstream->channels;
|
||||
}
|
||||
}
|
||||
else // Nana (2005)(Konami)
|
||||
{
|
||||
vgmstream->sample_rate = read_32bitLE(0x128,streamFile);
|
||||
vgmstream->num_samples = read_32bitLE(0x7F8,streamFile)/16*28/vgmstream->channels;
|
||||
if (loop_flag)
|
||||
{
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = read_32bitLE(0x7F8,streamFile)/16*28/vgmstream->channels;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
|
||||
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = read_32bitLE(0x4C,streamFile)/2;
|
||||
vgmstream->meta_type = meta_RWS;
|
||||
|
||||
/* 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;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
|
@ -253,7 +253,7 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
|||
else if (!strcasecmp("sns",filename_extension(filename)))
|
||||
sns = 1;
|
||||
#if defined(VGM_USE_MAIATRAC3PLUS) || defined(VGM_USE_FFMPEG)
|
||||
else if (!strcasecmp("at3",filename_extension(filename)))
|
||||
else if ( check_extensions(streamFile, "at3,rws") ) /* Renamed .RWS AT3 found in Climax games (Silent Hill Origins PSP, Oblivion PSP) */
|
||||
at3 = 1;
|
||||
#endif
|
||||
else
|
||||
|
|
|
@ -0,0 +1,181 @@
|
|||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../layout/layout.h"
|
||||
|
||||
|
||||
static off_t get_rws_string_size(off_t off, STREAMFILE *streamFile);
|
||||
|
||||
|
||||
/* RWS - RenderWare Stream (from games using RenderWare Audio middleware) */
|
||||
VGMSTREAM * init_vgmstream_rws(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset, off, coefs_offset = 0, stream_offset = 0;
|
||||
int loop_flag = 0, channel_count, codec;
|
||||
size_t file_size, header_size, data_size, stream_size = 0, info_size;
|
||||
int block_size_max = 0, block_size = 0, sample_rate;
|
||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
|
||||
int i, total_segments, total_streams, target_stream = 0;
|
||||
|
||||
|
||||
if (!check_extensions(streamFile,"rws"))
|
||||
goto fail;
|
||||
|
||||
/* check chunks (always LE) */
|
||||
/* Made of a file chunk with header and data chunks (other chunks exist for non-audio .RWS).
|
||||
* A chunk is: id, size, RW version (no real diffs), data of size (version is repeated but same for all chunks).
|
||||
* Version: 16b main + 16b build (can vary between files) ex: 0c02, 1003, 1400 = 3.5, 1803 = 3.6, 1C02 = 3.7. */
|
||||
if (read_32bitLE(0x00,streamFile) != 0x0000080d) /* audio file chunk id */
|
||||
goto fail;
|
||||
file_size = read_32bitLE(0x04,streamFile); /* audio file chunk size */
|
||||
if (file_size + 0x0c != get_streamfile_size(streamFile)) goto fail;
|
||||
|
||||
if (read_32bitLE(0x0c,streamFile) != 0x0000080e) /* header chunk id */
|
||||
goto fail;
|
||||
header_size = read_32bitLE(0x10,streamFile); /* header chunk size */
|
||||
|
||||
off = 0x0c + 0x0c + header_size;
|
||||
if (read_32bitLE(off+0x00,streamFile) != 0x0000080f) /* data chunk id */
|
||||
goto fail;
|
||||
data_size = read_32bitLE(off+0x04,streamFile); /* data chunk size */
|
||||
if (data_size+0x0c + off != get_streamfile_size(streamFile))
|
||||
goto fail;
|
||||
|
||||
/* inside header chunk (many unknown fields are probably IDs/config, as two same-sized files vary a lot) */
|
||||
off = 0x0c + 0x0c;
|
||||
|
||||
/* 0x00: actual header size (less than chunk size), useful to check endianness (Wii/X360 = BE) */
|
||||
read_32bit = (read_32bitLE(off+0x00,streamFile) > header_size) ? read_32bitBE : read_32bitLE;
|
||||
|
||||
/* 0x04-14: sizes of various sections?, others: ? */
|
||||
total_segments = read_32bit(off+0x20,streamFile);
|
||||
total_streams = read_32bit(off+0x28,streamFile);
|
||||
/* 0x2c: unk, 0x30: 0x800?, 0x34: max block size?, 0x38: data offset, 0x3c: 0?, 0x40-50: file uuid? */
|
||||
off += 0x50 + get_rws_string_size(off+0x50, streamFile); /* skip audio file name */
|
||||
|
||||
/* check streams/segments */
|
||||
/* Data can be divided into segments (cues/divisions within data, ex. intro+main, voice1+2+..N) or
|
||||
* tracks/streams in interleaved blocks that can contain padding and don't need to match between tracks
|
||||
* (ex 0x1800 data + 0 pad of stream_0 2ch, 0x1800 data + 0x200 pad of stream1 2ch, etc). */
|
||||
if (target_stream == 0) target_stream = 1;
|
||||
if (target_stream < 0 || target_stream > total_streams || total_streams < 1) goto fail;
|
||||
|
||||
/* skip segment stuff and get stream size (from sizes for all segments, repeated per track) */
|
||||
off += 0x20 * total_segments; /* segment data (mostly unknown except @ 0x18: full data size, 0x1c: offset) */
|
||||
for (i = 0; i < total_segments; i++) { /* sum usable segment sizes (no padding) */
|
||||
stream_size += read_32bit(off + 0x04 * i + total_segments*(target_stream-1),streamFile);
|
||||
}
|
||||
off += 0x04 * (total_segments * total_streams);
|
||||
off += 0x10 * total_segments; /* segment uuids? */
|
||||
for (i = 0; i < total_segments; i++) { /* skip segments names */
|
||||
off += get_rws_string_size(off, streamFile);
|
||||
}
|
||||
|
||||
/* get stream layout: 0xc: samples per frame (ex. 28 in VAG), 0x24: offset within data chunk, others: ? */
|
||||
/* get block_size for our target stream and from all streams, to skip their blocks during decode */
|
||||
for (i = 0; i < total_streams; i++) { /* get block_sizes */
|
||||
block_size_max += read_32bit(off+0x10 + 0x28*i,streamFile); /* includes padding and can be different per stream */
|
||||
if (target_stream-1 == i) {
|
||||
block_size = read_32bit(off+0x20 + 0x28*i,streamFile); /* actual size */
|
||||
stream_offset = read_32bit(off+0x24 + 0x28*i,streamFile); /* within data */
|
||||
}
|
||||
}
|
||||
off += 0x28 * total_streams;
|
||||
|
||||
/* get stream config: 0x0c(1): bits per sample, others: ? */
|
||||
info_size = total_streams > 1 ? 0x30 : 0x2c; //todo this doesn't look right
|
||||
sample_rate = read_32bit(off+0x00 + info_size*(target_stream-1),streamFile);
|
||||
//unk_size = read_32bit(off+0x08 + info_size*(target_stream-1),streamFile); /* segment size? loop-related? */
|
||||
channel_count = read_8bit(off+0x0d + info_size*(target_stream-1),streamFile);
|
||||
codec = read_32bitBE(off+0x1c + info_size*(target_stream-1),streamFile); /* uuid of 128b but the first is enough */
|
||||
off += info_size * total_streams;
|
||||
|
||||
|
||||
/* if codec is DSP there is an extra field */
|
||||
if (codec == 0xF86215B0) {
|
||||
/* 0x00: approx num samples? 0x04: approx size? */
|
||||
coefs_offset = off + 0x1c;
|
||||
}
|
||||
|
||||
/* next is 0x14 * streams = ?(4) + uuid? (header ends), rest is garbage/padding until chunk end (may contain strings and weird stuff) */
|
||||
|
||||
start_offset = 0x0c + 0x0c + header_size + 0x0c + stream_offset; /* usually 0x800 but not always */
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_RWS;
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->num_streams = total_streams;
|
||||
|
||||
vgmstream->layout_type = layout_rws_blocked;
|
||||
vgmstream->current_block_size = block_size / vgmstream->channels;
|
||||
vgmstream->full_block_size = block_size_max;
|
||||
|
||||
switch(codec) {
|
||||
case 0xD01BD217: /* PCM X360 (D01BD217 35874EED B9D9B8E8 6EA9B995) */
|
||||
/* The Legend of Spyro (X360) */
|
||||
vgmstream->coding_type = coding_PCM16BE;
|
||||
//vgmstream->interleave_block_size = block_size / 2; //0x2; //todo 2ch PCM not working correctly (interleaved PCM not ok?)
|
||||
|
||||
vgmstream->num_samples = pcm_bytes_to_samples(stream_size, channel_count, 16);
|
||||
break;
|
||||
|
||||
case 0x9897EAD9: /* PS-ADPCM PS2 (9897EAD9 BCBB7B44 96B26547 59102E16) */
|
||||
/* ex. Silent Hill Origins (PS2), Ghost Rider (PS2), Max Payne 2 (PS2), Nana (PS2) */
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->interleave_block_size = block_size / 2;
|
||||
|
||||
vgmstream->num_samples = ps_bytes_to_samples(stream_size, channel_count);
|
||||
break;
|
||||
|
||||
case 0xF86215B0: /* DSP Wii (F86215B0 31D54C29 BD37CDBF 9BD10C53) */
|
||||
/* ex. Alice in Wonderland (Wii) */
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->interleave_block_size = block_size / 2;
|
||||
|
||||
/* get coefs (all channels share them so 0 spacing; also seem fixed for all RWS) */
|
||||
dsp_read_coefs_be(vgmstream,streamFile,coefs_offset, 0);
|
||||
|
||||
vgmstream->num_samples = dsp_bytes_to_samples(stream_size, channel_count);
|
||||
break;
|
||||
|
||||
case 0x936538EF: /* MS-IMA PC (936538EF 11B62D43 957FA71A DE44227A) */
|
||||
case 0x2BA22F63: /* MS-IMA Xbox (2BA22F63 DD118F45 AA27A5C3 46E9790E) */
|
||||
/* ex. Broken Sword 3 (PC), Jacked (PC/Xbox), Burnout 2 (Xbox) */
|
||||
vgmstream->coding_type = coding_XBOX;
|
||||
vgmstream->interleave_block_size = 0; /* uses regular XBOX/MS-IMA interleave */
|
||||
|
||||
vgmstream->num_samples = ms_ima_bytes_to_samples(stream_size, 0x48, channel_count);
|
||||
break;
|
||||
|
||||
default:
|
||||
VGM_LOG("RSW: unknown codec 0x%08x\n", codec);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
|
||||
rws_block_update(start_offset, vgmstream); /* block init */
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* rws-strings are null-terminated then padded to 0x10 (weirdly the padding contains garbage) */
|
||||
static off_t get_rws_string_size(off_t off, STREAMFILE *streamFile) {
|
||||
int i;
|
||||
for (i = 0; i < 0x800; i++) { /* 0x800=arbitrary max */
|
||||
if (read_8bit(off+i,streamFile) == 0) { /* null terminator */
|
||||
return i + (0x10 - (i % 0x10)); /* size is padded */
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -37,7 +37,7 @@ VGMSTREAM * init_vgmstream_xau(STREAMFILE *streamFile) {
|
|||
/* miniheader over a common header with some tweaks, so we'll simplify parsing */
|
||||
switch(type) {
|
||||
case 0x50533200: /* "PS2\0" */
|
||||
if (read_32bitBE(0x40,streamFile) != 0x56414770) goto fail; /* "VAGp" */
|
||||
if (read_32bitBE(0x40,streamFile) != 0x56414770) goto fail; /* mutant "VAGp" (long header size) */
|
||||
|
||||
start_offset = 0x800;
|
||||
vgmstream->sample_rate = read_32bitBE(0x50, streamFile);
|
||||
|
@ -48,22 +48,24 @@ VGMSTREAM * init_vgmstream_xau(STREAMFILE *streamFile) {
|
|||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x8000;
|
||||
|
||||
break;
|
||||
case 0x58420000: /* "XB\0\0" */
|
||||
if (read_32bitBE(0x40,streamFile) != 0x52494646) goto fail; /* "RIFF" */
|
||||
|
||||
start_offset = 0x70;
|
||||
case 0x58420000: /* "XB\0\0" */
|
||||
if (read_32bitBE(0x40,streamFile) != 0x52494646) goto fail; /* mutant "RIFF" (sometimes wrong RIFF size) */
|
||||
|
||||
/* start offset: find "data" chunk, as sometimes there is a "smpl" chunk at the start or the end (same as loop_start/end) */
|
||||
if (!find_chunk_le(streamFile, 0x64617461, 0x4c, 0, &start_offset, NULL) )
|
||||
goto fail;
|
||||
|
||||
vgmstream->sample_rate = read_32bitLE(0x58, streamFile);
|
||||
vgmstream->num_samples = ms_ima_bytes_to_samples(read_32bitLE(0x6c, streamFile), read_16bitLE(0x60, streamFile), channel_count);
|
||||
vgmstream->num_samples = ms_ima_bytes_to_samples(read_32bitLE(start_offset-4, streamFile), read_16bitLE(0x60, streamFile), channel_count);
|
||||
vgmstream->loop_start_sample = loop_start;
|
||||
vgmstream->loop_end_sample = loop_end;
|
||||
/* there is also a "smpl" chunk at the end, same as loop_start/end */
|
||||
|
||||
vgmstream->coding_type = coding_XBOX;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
|
|
@ -485,7 +485,8 @@ int check_extensions(STREAMFILE *streamFile, const char * cmp_exts) {
|
|||
char filename[PATH_LIMIT];
|
||||
const char * ext = NULL;
|
||||
const char * cmp_ext = NULL;
|
||||
int ext_len, cmp_len;
|
||||
const char * ststr_res = NULL;
|
||||
size_t ext_len, cmp_len;
|
||||
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
ext = filename_extension(filename);
|
||||
|
@ -493,14 +494,15 @@ int check_extensions(STREAMFILE *streamFile, const char * cmp_exts) {
|
|||
|
||||
cmp_ext = cmp_exts;
|
||||
do {
|
||||
cmp_len = strstr(cmp_ext, ",") - cmp_ext; /* find next ext; becomes negative if not found */
|
||||
if (cmp_len < 0)
|
||||
cmp_len = strlen(cmp_ext); /* total length if more not found */
|
||||
ststr_res = strstr(cmp_ext, ",");
|
||||
cmp_len = ststr_res == NULL
|
||||
? strlen(cmp_ext) /* total length if more not found */
|
||||
: (intptr_t)ststr_res - (intptr_t)cmp_ext; /* find next ext; ststr_res should always be greater than cmp_ext, resulting in a positive cmp_len */
|
||||
|
||||
if (strncasecmp(ext,cmp_ext, ext_len) == 0 && ext_len == cmp_len)
|
||||
if (ext_len == cmp_len && strncasecmp(ext,cmp_ext, ext_len) == 0)
|
||||
return 1;
|
||||
|
||||
cmp_ext = strstr(cmp_ext, ",");
|
||||
cmp_ext = ststr_res;
|
||||
if (cmp_ext != NULL)
|
||||
cmp_ext = cmp_ext + 1; /* skip comma */
|
||||
|
||||
|
|
|
@ -361,6 +361,7 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = {
|
|||
init_vgmstream_ta_aac_x360,
|
||||
init_vgmstream_ta_aac_ps3,
|
||||
init_vgmstream_ps3_mta2,
|
||||
init_vgmstream_ngc_ulw,
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
init_vgmstream_mp4_aac_ffmpeg,
|
||||
|
@ -936,6 +937,7 @@ void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstre
|
|||
case layout_tra_blocked:
|
||||
case layout_ps2_iab_blocked:
|
||||
case layout_ps2_strlr_blocked:
|
||||
case layout_rws_blocked:
|
||||
render_vgmstream_blocked(buffer,sample_count,vgmstream);
|
||||
break;
|
||||
case layout_interleave_byte:
|
||||
|
@ -979,6 +981,7 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
|
|||
case coding_PCM8_int:
|
||||
case coding_PCM8_SB_int:
|
||||
case coding_PCM8_U_int:
|
||||
case coding_ULAW:
|
||||
#ifdef VGM_USE_VORBIS
|
||||
case coding_ogg_vorbis:
|
||||
case coding_fsb_vorbis:
|
||||
|
@ -1136,6 +1139,7 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
|
|||
case coding_PCM8_int:
|
||||
case coding_PCM8_SB_int:
|
||||
case coding_PCM8_U_int:
|
||||
case coding_ULAW:
|
||||
case coding_SDX2:
|
||||
case coding_SDX2_int:
|
||||
case coding_CBD2:
|
||||
|
@ -1356,6 +1360,13 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
|
|||
samples_to_do);
|
||||
}
|
||||
break;
|
||||
case coding_ULAW:
|
||||
for (chan=0;chan<vgmstream->channels;chan++) {
|
||||
decode_ulaw(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
|
||||
vgmstream->channels,vgmstream->samples_into_block,
|
||||
samples_to_do);
|
||||
}
|
||||
break;
|
||||
case coding_NDS_IMA:
|
||||
for (chan=0;chan<vgmstream->channels;chan++) {
|
||||
decode_nds_ima(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
|
||||
|
|
|
@ -91,6 +91,7 @@ typedef enum {
|
|||
coding_PCM8_U, /* 8-bit PCM, unsigned (0x80 = 0) */
|
||||
coding_PCM8_U_int, /* 8-bit PCM, unsigned (0x80 = 0) with sample-level interleave */
|
||||
coding_PCM8_SB_int, /* 8-bit PCM, sign bit (others are 2's complement) with sample-level interleave */
|
||||
coding_ULAW, /* 8-bit u-Law (non-linear PCM) */
|
||||
|
||||
/* 4-bit ADPCM */
|
||||
coding_CRI_ADX, /* CRI ADX */
|
||||
|
@ -242,6 +243,7 @@ typedef enum {
|
|||
layout_tra_blocked, /* DefJam Rapstar .tra blocks */
|
||||
layout_ps2_iab_blocked,
|
||||
layout_ps2_strlr_blocked,
|
||||
layout_rws_blocked,
|
||||
|
||||
/* otherwise odd */
|
||||
layout_acm, /* libacm layout */
|
||||
|
@ -347,7 +349,7 @@ typedef enum {
|
|||
meta_SL3, /* Test Drive Unlimited */
|
||||
meta_HGC1, /* Knights of the Temple 2 */
|
||||
meta_AUS, /* Various Capcom games */
|
||||
meta_RWS, /* Various Konami games */
|
||||
meta_RWS, /* RenderWare games (only when using RW Audio middleware) */
|
||||
meta_FSB1, /* FMOD Sample Bank, version 1 */
|
||||
meta_FSB2, /* FMOD Sample Bank, version 2 */
|
||||
meta_FSB3, /* FMOD Sample Bank, version 3.0/3.1 */
|
||||
|
@ -625,6 +627,7 @@ typedef enum {
|
|||
meta_TA_AAC_X360, /* tri-ace AAC (Star Ocean 4, End of Eternity, Infinite Undiscovery) */
|
||||
meta_TA_AAC_PS3, /* tri-ace AAC (Star Ocean International, Resonance of Fate) */
|
||||
meta_PS3_MTA2, /* Metal Gear Solid 4 MTA2 */
|
||||
meta_NGC_ULW, /* Burnout 1 (GC only) */
|
||||
|
||||
#ifdef VGM_USE_VORBIS
|
||||
meta_OGG_VORBIS, /* Ogg Vorbis */
|
||||
|
@ -732,10 +735,12 @@ typedef struct {
|
|||
size_t interleave_smallblock_size; /* smaller interleave for last block */
|
||||
/* headered blocks */
|
||||
off_t current_block_offset; /* start of this block (offset of block header) */
|
||||
size_t current_block_size; /* size of the block we're in now */
|
||||
size_t current_block_size; /* size of the block we're in now (usable data) */
|
||||
size_t full_block_size; /* size including padding and other unusable data */
|
||||
off_t next_block_offset; /* offset of header of the next block */
|
||||
int block_count; /* count of "semi" block in total block */
|
||||
|
||||
|
||||
/* loop layout (saved values) */
|
||||
int32_t loop_sample; /* saved from current_sample, should be loop_start_sample... */
|
||||
int32_t loop_samples_into_block;/* saved from samples_into_block */
|
||||
|
|
Loading…
Reference in New Issue