Updated VGMStream to r1050-532-gba4e6d1f.

CQTexperiment
Christopher Snowhill 2017-06-11 17:35:03 -07:00
parent d2dc14a72c
commit 5df7a8f5c6
17 changed files with 371 additions and 133 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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