Updated VGMStream to r1050-3861-g0ad117e8

CQTexperiment
Christopher Snowhill 2021-08-05 00:26:13 -07:00
parent 0a7be8ab41
commit 8622829af7
94 changed files with 2524 additions and 2273 deletions

View File

@ -175,6 +175,8 @@
8349A91F1FE6258200E26435 /* naac.c in Sources */ = {isa = PBXBuildFile; fileRef = 8349A9061FE6258100E26435 /* naac.c */; };
834D3A6E19F47C98001C54F6 /* g1l.c in Sources */ = {isa = PBXBuildFile; fileRef = 834D3A6D19F47C98001C54F6 /* g1l.c */; };
834D795520E4F0D400C4A5CC /* Vorbis.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 83F4128F1E932F9A002E37D0 /* Vorbis.framework */; };
834FBCE826BBC7D00095647F /* tantalus_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 834FBCE426BBC7D00095647F /* tantalus_decoder.c */; };
834FBCEA26BBC7E50095647F /* piff_tpcm.c in Sources */ = {isa = PBXBuildFile; fileRef = 834FBCE926BBC7E50095647F /* piff_tpcm.c */; };
834FE0B3215C798C000A5D3D /* acm_decoder_util.c in Sources */ = {isa = PBXBuildFile; fileRef = 834FE0AA215C798A000A5D3D /* acm_decoder_util.c */; };
834FE0B4215C798C000A5D3D /* ffmpeg_decoder_custom_opus.c in Sources */ = {isa = PBXBuildFile; fileRef = 834FE0AB215C798A000A5D3D /* ffmpeg_decoder_custom_opus.c */; };
834FE0B5215C798C000A5D3D /* acm_decoder_libacm.h in Headers */ = {isa = PBXBuildFile; fileRef = 834FE0AC215C798B000A5D3D /* acm_decoder_libacm.h */; };
@ -967,6 +969,8 @@
8349A9051FE6258100E26435 /* bar.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bar.c; sourceTree = "<group>"; };
8349A9061FE6258100E26435 /* naac.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = naac.c; sourceTree = "<group>"; };
834D3A6D19F47C98001C54F6 /* g1l.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = g1l.c; sourceTree = "<group>"; };
834FBCE426BBC7D00095647F /* tantalus_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tantalus_decoder.c; sourceTree = "<group>"; };
834FBCE926BBC7E50095647F /* piff_tpcm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = piff_tpcm.c; sourceTree = "<group>"; };
834FE0AA215C798A000A5D3D /* acm_decoder_util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = acm_decoder_util.c; sourceTree = "<group>"; };
834FE0AB215C798A000A5D3D /* ffmpeg_decoder_custom_opus.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffmpeg_decoder_custom_opus.c; sourceTree = "<group>"; };
834FE0AC215C798B000A5D3D /* acm_decoder_libacm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = acm_decoder_libacm.h; sourceTree = "<group>"; };
@ -1680,6 +1684,7 @@
83E7FD5B25EF2B0C00683FD2 /* tac_decoder_lib.c */,
83E7FD5C25EF2B0C00683FD2 /* tac_decoder_lib.h */,
83E7FD5725EF2B0C00683FD2 /* tac_decoder.c */,
834FBCE426BBC7D00095647F /* tantalus_decoder.c */,
8373341023F60C7A00DE14DC /* tgcadpcm_decoder.c */,
837CEA7623487E2400E62A4A /* ubi_adpcm_decoder.c */,
83F1EE2C245D4FB20076E182 /* vadpcm_decoder.c */,
@ -1989,6 +1994,7 @@
836F6E8618BDC2180095E648 /* pc_mxst.c */,
8306B0D12098458F000302D4 /* pcm_sre.c */,
83D20076248DDB770048BD24 /* pcm_success.c */,
834FBCE926BBC7E50095647F /* piff_tpcm.c */,
836F6E8B18BDC2180095E648 /* pona.c */,
836F6E8C18BDC2180095E648 /* pos.c */,
8306B0C52098458D000302D4 /* ppst_streamfile.h */,
@ -2741,6 +2747,7 @@
836F6FC118BDC2190095E648 /* pc_adp.c in Sources */,
836F703B18BDC2190095E648 /* vsf.c in Sources */,
836F6F8218BDC2190095E648 /* ea_schl.c in Sources */,
834FBCE826BBC7D00095647F /* tantalus_decoder.c in Sources */,
836F6F7318BDC2190095E648 /* bcstm.c in Sources */,
83299FD11E7660C7003A3242 /* dsp_adx.c in Sources */,
836F704018BDC2190095E648 /* wii_sng.c in Sources */,
@ -2987,6 +2994,7 @@
836F704F18BDC2190095E648 /* xwb.c in Sources */,
8346D98525BF83B300D1A8B0 /* compresswave_decoder_lib.c in Sources */,
8346D97D25BF838C00D1A8B0 /* compresswave.c in Sources */,
834FBCEA26BBC7E50095647F /* piff_tpcm.c in Sources */,
8306B0AD20984552000302D4 /* blocked_caf.c in Sources */,
8306B0AA20984552000302D4 /* blocked_sthd.c in Sources */,
836F6FE918BDC2190095E648 /* ps2_mihb.c in Sources */,

View File

@ -364,7 +364,7 @@ static void clHCA_destructor(clHCA* hca) {
hca->is_valid = 0;
}
int clHCA_sizeof() {
int clHCA_sizeof(void) {
return sizeof(clHCA);
}
@ -376,7 +376,7 @@ void clHCA_done(clHCA* hca) {
clHCA_destructor(hca);
}
clHCA* clHCA_new() {
clHCA* clHCA_new(void) {
clHCA* hca = malloc(clHCA_sizeof());
if (hca) {
clHCA_constructor(hca);
@ -1941,7 +1941,6 @@ static void imdct_transform(stChannel* ch, int subframe) {
/* update output/imdct with overlapped window (lib fuses this with the above) */
{
unsigned int i;
const float* dct = ch->spectra; //ch->dct;
const float* prev = ch->imdct_previous;

View File

@ -14,12 +14,12 @@ int clHCA_isOurFile(const void *data, unsigned int size);
typedef struct clHCA clHCA;
/* In case you wish to allocate and reset the structure on your own. */
int clHCA_sizeof();
int clHCA_sizeof(void);
void clHCA_clear(clHCA *);
void clHCA_done(clHCA *);
/* Or you could let the library allocate it. */
clHCA * clHCA_new();
clHCA * clHCA_new(void);
void clHCA_delete(clHCA *);
/* Parses the HCA header. Must be called before any decoding may be performed,

View File

@ -90,7 +90,7 @@ void decode_circus_adpcm(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channel
for (i = first_sample; i < first_sample + samples_to_do; i++) {
int8_t code = read_8bit(frame_offset+i,stream->streamfile);
int8_t code = read_u8(frame_offset+i,stream->streamfile);
hist += code << scale;
if (code == 0) {
@ -102,6 +102,7 @@ void decode_circus_adpcm(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channel
scale++;
}
outbuf[sample_pos] = hist;
sample_pos += channelspacing;
}
stream->adpcm_history1_32 = hist;

View File

@ -35,12 +35,12 @@ void decode_rad_ima(VGMSTREAM* vgmstream, VGMSTREAMCHANNEL* stream, sample_t* ou
void decode_rad_ima_mono(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_apple_ima4(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_fsb_ima(VGMSTREAM* vgmstream, VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_wwise_ima(VGMSTREAM* vgmstream, VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_wwise_ima(VGMSTREAM* vgmstream, VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_awc_ima(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_ubi_ima(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_ubi_sce_ima(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_h4m_ima(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, uint16_t frame_format);
void decode_cd_ima(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_cd_ima(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
size_t ima_bytes_to_samples(size_t bytes, int channels);
size_t ms_ima_bytes_to_samples(size_t bytes, int block_align, int channels);
size_t xbox_ima_bytes_to_samples(size_t bytes, int channels);
@ -118,13 +118,13 @@ size_t xa_bytes_to_samples(size_t bytes, int channels, int is_blocked, int is_fo
/* ea_xa_decoder */
void decode_ea_xa(VGMSTREAMCHANNEL* stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo);
void decode_ea_xa_v2(VGMSTREAMCHANNEL* stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);
void decode_ea_xa_v2(VGMSTREAMCHANNEL* stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_maxis_xa(VGMSTREAMCHANNEL* stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
int32_t ea_xa_bytes_to_samples(size_t bytes, int channels);
/* ea_xas_decoder */
void decode_ea_xas_v0(VGMSTREAMCHANNEL* stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_ea_xas_v0(VGMSTREAMCHANNEL* stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_ea_xas_v1(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
@ -224,6 +224,11 @@ void decode_dsa(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing,
void decode_xmd(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, size_t frame_size);
/* tantalus_decoder */
void decode_tantalus(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
int32_t tantalus_bytes_to_samples(size_t bytes, int channels);
/* derf_decoder */
void decode_derf(VGMSTREAMCHANNEL* stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
@ -336,12 +341,12 @@ void free_tac(tac_codec_data* data);
typedef struct ogg_vorbis_codec_data ogg_vorbis_codec_data;
typedef struct { //todo simplify
STREAMFILE *streamfile;
ogg_int64_t start; /* file offset where the Ogg starts */
ogg_int64_t offset; /* virtual offset, from 0 to size */
ogg_int64_t size; /* virtual size of the Ogg */
int64_t start; /* file offset where the Ogg starts */
int64_t offset; /* virtual offset, from 0 to size */
int64_t size; /* virtual size of the Ogg */
/* decryption setup */
void (*decryption_callback)(void *ptr, size_t size, size_t nmemb, void *datasource);
void (*decryption_callback)(void* ptr, size_t size, size_t nmemb, void* datasource);
uint8_t scd_xor;
off_t scd_xor_length;
uint32_t xor_value;
@ -552,6 +557,8 @@ void free_speex(speex_codec_data* data);
#ifdef VGM_USE_FFMPEG
/* ffmpeg_decoder */
typedef struct ffmpeg_codec_data ffmpeg_codec_data;
ffmpeg_codec_data* init_ffmpeg_offset(STREAMFILE* sf, uint64_t start, uint64_t size);
ffmpeg_codec_data* init_ffmpeg_header_offset(STREAMFILE* sf, uint8_t* header, uint64_t header_size, uint64_t start, uint64_t size);
ffmpeg_codec_data* init_ffmpeg_header_offset_subsong(STREAMFILE* sf, uint8_t* header, uint64_t header_size, uint64_t start, uint64_t size, int target_subsong);
@ -566,13 +573,20 @@ uint32_t ffmpeg_get_channel_layout(ffmpeg_codec_data* data);
void ffmpeg_set_channel_remapping(ffmpeg_codec_data* data, int* channels_remap);
const char* ffmpeg_get_codec_name(ffmpeg_codec_data* data);
void ffmpeg_set_force_seek(ffmpeg_codec_data* data);
void ffmpeg_set_invert_floats(ffmpeg_codec_data* data);
const char* ffmpeg_get_metadata_value(ffmpeg_codec_data* data, const char* key);
int32_t ffmpeg_get_samples(ffmpeg_codec_data* data);
int ffmpeg_get_sample_rate(ffmpeg_codec_data* data);
int ffmpeg_get_channels(ffmpeg_codec_data* data);
int ffmpeg_get_subsong_count(ffmpeg_codec_data* data);
STREAMFILE* ffmpeg_get_streamfile(ffmpeg_codec_data* data);
/* ffmpeg_decoder_utils.c (helper-things) */
ffmpeg_codec_data* init_ffmpeg_atrac3_raw(STREAMFILE* sf, off_t offset, size_t data_size, int sample_count, int channels, int sample_rate, int block_align, int encoder_delay);
ffmpeg_codec_data* init_ffmpeg_atrac3_riff(STREAMFILE* sf, off_t offset, int* out_samples);
ffmpeg_codec_data* init_ffmpeg_aac(STREAMFILE* sf, off_t offset, size_t size);
ffmpeg_codec_data* init_ffmpeg_aac(STREAMFILE* sf, off_t offset, size_t size, int skip_samples);
/* ffmpeg_decoder_custom_opus.c (helper-things) */

View File

@ -829,9 +829,7 @@ void xma_fix_raw_samples_ch(VGMSTREAM* vgmstream, STREAMFILE* sf, off_t stream_o
* Somehow also needs to skip 64 extra samples (looks like another FFmpeg bug
* where XMA outputs half a subframe samples late, WMAPRO isn't affected),
* which sometimes makes FFmpeg complain (=reads after end) but doesn't seem audible. */
if (data->skipSamples == 0) {
ffmpeg_set_skip_samples(data, start_skip+64);
}
ffmpeg_set_skip_samples(data, start_skip+64);
}
#endif
}

View File

@ -557,7 +557,7 @@ struct TCompressWaveData {
//-----------------------------------------------------------
//create
TCompressWaveData* TCompressWaveData_Create() {
TCompressWaveData* TCompressWaveData_Create(void) {
TCompressWaveData* this = malloc(sizeof(TCompressWaveData));
if (!this) return NULL;
#if 0
@ -604,7 +604,7 @@ void TCompressWaveData_Free(TCompressWaveData* this) {
//-----------------------------------------------------------
//outpus 44100/16bit/stereo waveform to designed buffer
void TCompressWaveData_Rendering_ReadPress(TCompressWaveData* this, int32_t* RFlg, int32_t* LFlg) {
static void TCompressWaveData_Rendering_ReadPress(TCompressWaveData* this, int32_t* RFlg, int32_t* LFlg) {
if (this->Hed.Channel == 2) {
*RFlg = THuff_Read(this->RH); //STEREO
*LFlg = THuff_Read(this->RH);
@ -615,7 +615,7 @@ void TCompressWaveData_Rendering_ReadPress(TCompressWaveData* this, int32_t* RFl
}
}
void TCompressWaveData_Rendering_WriteWave(TCompressWaveData* this, int16_t** buf1, int32_t RVol, int32_t LVol) {
static void TCompressWaveData_Rendering_WriteWave(TCompressWaveData* this, int16_t** buf1, int32_t RVol, int32_t LVol) {
TLRWRITEBUFFER bbb = {0};
if (this->Hed.Sample == 44100) { //44100 STEREO/MONO
@ -867,8 +867,8 @@ void TCompressWaveData_SetVolume(TCompressWaveData* this, float vol, float fade)
this->FSetVolume = this->FVolume;
}
else { //without fade value
this->Ffade = round(PW_MAXVOLUME / fade / 44100);
this->FSetVolume = round(aaa * PW_MAXVOLUME);
this->Ffade = round((double)PW_MAXVOLUME / fade / 44100);
this->FSetVolume = round(aaa * (double)PW_MAXVOLUME);
}
}

View File

@ -7,7 +7,7 @@ typedef struct TCompressWaveData TCompressWaveData;
void TCompressWaveData_GetLoopState(TCompressWaveData* this);
void TCompressWaveData_SetLoopState(TCompressWaveData* this);
TCompressWaveData* TCompressWaveData_Create();
TCompressWaveData* TCompressWaveData_Create(void);
void TCompressWaveData_Free(TCompressWaveData* this);
int TCompressWaveData_Rendering(TCompressWaveData* this, int16_t* buf, uint32_t Len);
int TCompressWaveData_LoadFromStream(TCompressWaveData* this, STREAMFILE* ss);

View File

@ -30,7 +30,7 @@ static const int EA_XA_TABLE[20] = {
};
/* EA XA v2 (always mono); like v1 but with "PCM samples" flag and doesn't add 128 on expand or clamp (pre-adjusted by the encoder?) */
void decode_ea_xa_v2(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
void decode_ea_xa_v2(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
uint8_t frame_info;
int32_t coef1, coef2;
int i, sample_count, shift;
@ -60,7 +60,7 @@ void decode_ea_xa_v2(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspac
coef2 = EA_XA_TABLE[(frame_info >> 4) + 4];
shift = (frame_info & 0x0F) + 8;
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++, sample_count += channelspacing) {
uint8_t sample_byte, sample_nibble;
int32_t new_sample;
off_t byte_offset = (stream->offset + 0x01 + i/2);
@ -84,7 +84,7 @@ void decode_ea_xa_v2(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspac
}
#if 0
/* later PC games use float math, though in the end sounds basically the same (decompiled from various exes) */
/* later PC games and EAAC use float math, though in the end sounds basically the same (decompiled from various exes) */
static const double XA_K0[16] = { 0.0, 0.9375, 1.796875, 1.53125 };
static const double XA_K1[16] = { 0.0, 0.0, -0.8125, -0.859375 };
/* code uses look-up table but it's equivalent to:
@ -125,7 +125,7 @@ static const uint32_t FLOAT_TABLE_INT[256] = {
};
static const float* FLOAT_TABLE = (const float *)FLOAT_TABLE_INT;
void decode_ea_xa_v2(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
void decode_ea_xa_v2_f32(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
uint8_t frame_info;
int i, sample_count, shift;

View File

@ -113,7 +113,7 @@ void decode_ea_xas_v1(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspa
/* EA-XAS v0 (xas0), without complex layouts and closer to EA-XA. Somewhat based on daemon1's decoder. */
void decode_ea_xas_v0(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
void decode_ea_xas_v0(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
uint8_t frame[0x13] = {0};
off_t frame_offset;
int i, frames_in, samples_done = 0, sample_count = 0;

View File

@ -2,10 +2,61 @@
#include "coding.h"
#ifdef VGM_USE_FFMPEG
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswresample/swresample.h>
/* opaque struct */
struct ffmpeg_codec_data {
/*** IO internals ***/
STREAMFILE* sf;
uint64_t start; // absolute start within the streamfile
uint64_t offset; // absolute offset within the streamfile
uint64_t size; // max size within the streamfile
uint64_t logical_offset; // computed offset FFmpeg sees (including fake header)
uint64_t logical_size; // computed size FFmpeg sees (including fake header)
uint64_t header_size; // fake header (parseable by FFmpeg) prepended on reads
uint8_t* header_block; // fake header data (ie. RIFF)
/*** internal state ***/
// config
int stream_count; /* FFmpeg audio streams (ignores video/etc) */
int stream_index;
int64_t total_samples; /* may be 0 and innacurate */
int64_t skip_samples; /* number of start samples that will be skipped (encoder delay) */
int channel_remap_set;
int channel_remap[32]; /* map of channel > new position */
int invert_floats_set;
int skip_samples_set; /* flag to know skip samples were manually added from vgmstream */
int force_seek; /* flags for special seeking in faulty formats */
int bad_init;
// FFmpeg context used for metadata
AVCodec* codec;
/* FFmpeg decoder state */
unsigned char* buffer;
AVIOContext* ioCtx;
AVFormatContext* formatCtx;
AVCodecContext* codecCtx;
AVFrame* frame; /* last decoded frame */
AVPacket* packet; /* last read data packet */
int read_packet;
int end_of_stream;
int end_of_audio;
/* sample state */
int32_t samples_discard;
int32_t samples_consumed;
int32_t samples_filled;
};
#define FFMPEG_DEFAULT_IO_BUFFER_SIZE 128 * 1024
static volatile int g_ffmpeg_initialized = 0;
static void free_ffmpeg_config(ffmpeg_codec_data* data);
@ -16,7 +67,7 @@ static int init_ffmpeg_config(ffmpeg_codec_data* data, int target_subsong, int r
/* ******************************************** */
/* Global FFmpeg init */
static void g_init_ffmpeg() {
static void g_init_ffmpeg(void) {
if (g_ffmpeg_initialized == 1) {
while (g_ffmpeg_initialized < 2); /* active wait for lack of a better way */
}
@ -69,8 +120,8 @@ static int init_seek(ffmpeg_codec_data* data) {
int size = 0; /* data size (block align) */
int distance = 0; /* always 0 ("duration") */
AVStream * stream = data->formatCtx->streams[data->streamIndex];
AVPacket * pkt = data->packet;
AVStream* stream = data->formatCtx->streams[data->stream_index];
AVPacket* pkt = data->packet;
/* read_seek shouldn't need this index, but direct access to FFmpeg's internals is no good */
@ -95,7 +146,7 @@ static int init_seek(ffmpeg_codec_data* data) {
ret = av_read_frame(data->formatCtx, pkt);
if (ret < 0)
break;
if (pkt->stream_index != data->streamIndex)
if (pkt->stream_index != data->stream_index)
continue; /* ignore non-selected streams */
//;VGM_LOG("FFMPEG: packet %i, ret=%i, pos=%i, dts=%i\n", packet_count, ret, (int32_t)pkt->pos, (int32_t)pkt->dts);
@ -138,7 +189,7 @@ static int init_seek(ffmpeg_codec_data* data) {
test_seek:
/* seek to 0 test + move back to beginning, since we just consumed packets */
ret = avformat_seek_file(data->formatCtx, data->streamIndex, ts, ts, ts, AVSEEK_FLAG_ANY);
ret = avformat_seek_file(data->formatCtx, data->stream_index, ts, ts, ts, AVSEEK_FLAG_ANY);
if ( ret < 0 ) {
//char test[1000] = {0}; av_strerror(ret, test, 1000); VGM_LOG("FFMPEG: ret=%i %s\n", ret, test);
return ret; /* we can't even reset_vgmstream the file */
@ -186,7 +237,7 @@ static int ffmpeg_read(void* opaque, uint8_t* buf, int read_size) {
}
/* main read */
bytes = read_streamfile(buf, data->offset, read_size, data->streamfile);
bytes = read_streamfile(buf, data->offset, read_size, data->sf);
data->logical_offset += bytes;
data->offset += bytes;
return bytes + max_to_copy;
@ -215,6 +266,9 @@ static int64_t ffmpeg_seek(void* opaque, int64_t offset, int whence) {
case SEEK_END: /* relative to file end (should be negative) */
offset += data->logical_size;
break;
default:
break;
}
/* clamp offset; fseek does this too */
@ -244,7 +298,7 @@ ffmpeg_codec_data* init_ffmpeg_offset(STREAMFILE* sf, uint64_t start, uint64_t s
return init_ffmpeg_header_offset(sf, NULL,0, start,size);
}
ffmpeg_codec_data* init_ffmpeg_header_offset(STREAMFILE* sf, uint8_t * header, uint64_t header_size, uint64_t start, uint64_t size) {
ffmpeg_codec_data* init_ffmpeg_header_offset(STREAMFILE* sf, uint8_t* header, uint64_t header_size, uint64_t start, uint64_t size) {
return init_ffmpeg_header_offset_subsong(sf, header, header_size, start, size, 0);
}
@ -281,8 +335,8 @@ ffmpeg_codec_data* init_ffmpeg_header_offset_subsong(STREAMFILE* sf, uint8_t* he
data = calloc(1, sizeof(ffmpeg_codec_data));
if (!data) return NULL;
data->streamfile = reopen_streamfile(sf, 0);
if (!data->streamfile) goto fail;
data->sf = reopen_streamfile(sf, 0);
if (!data->sf) goto fail;
/* fake header to trick FFmpeg into demuxing/decoding the stream */
if (header_size > 0) {
@ -307,14 +361,16 @@ ffmpeg_codec_data* init_ffmpeg_header_offset_subsong(STREAMFILE* sf, uint8_t* he
/* setup other values */
{
AVStream *stream = data->formatCtx->streams[data->streamIndex];
AVStream* stream = data->formatCtx->streams[data->stream_index];
AVRational tb = {0};
tb.num = 1; tb.den = data->codecCtx->sample_rate;
#if 0
/* derive info */
data->sampleRate = data->codecCtx->sample_rate;
data->channels = data->codecCtx->channels;
data->bitrate = (int)(data->codecCtx->bit_rate);
#if 0
data->blockAlign = data->codecCtx->block_align;
data->frameSize = data->codecCtx->frame_size;
if(data->frameSize == 0) /* some formats don't set frame_size but can get on request, and vice versa */
@ -322,40 +378,40 @@ ffmpeg_codec_data* init_ffmpeg_header_offset_subsong(STREAMFILE* sf, uint8_t* he
#endif
/* try to guess frames/samples (duration isn't always set) */
tb.num = 1; tb.den = data->codecCtx->sample_rate;
data->totalSamples = av_rescale_q(stream->duration, stream->time_base, tb);
if (data->totalSamples < 0)
data->totalSamples = 0; /* caller must consider this */
data->total_samples = av_rescale_q(stream->duration, stream->time_base, tb);
if (data->total_samples < 0)
data->total_samples = 0;
/* expose start samples to be skipped (encoder delay, usually added by MDCT-based encoders like AAC/MP3/ATRAC3/XMA/etc)
* get after init_seek because some demuxers like AAC only fill skip_samples for the first packet */
#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 64, 100)
if (stream->start_skip_samples) /* samples to skip in the first packet */
data->skipSamples = stream->start_skip_samples;
/* read start samples to be skipped (encoder delay), info only.
* Not too reliable though, see ffmpeg_set_skip_samples */
if (stream->start_time && stream->start_time != AV_NOPTS_VALUE)
data->skip_samples = av_rescale_q(stream->start_time, stream->time_base, tb);
if (data->skip_samples < 0)
data->skip_samples = 0;
#if 0 //LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 64, 100)
/* exposed before but not too reliable either */
else if (stream->start_skip_samples) /* samples to skip in the first packet */
data->skip_samples = stream->start_skip_samples;
else if (stream->skip_samples) /* samples to skip in any packet (first in this case), used sometimes instead (ex. AAC) */
data->skipSamples = stream->skip_samples;
#else
if (stream->start_time)
data->skipSamples = av_rescale_q(stream->start_time, stream->time_base, tb);
data->skip_samples = stream->skip_samples;
#endif
/* check ways to skip encoder delay/padding, for debugging purposes (some may be old/unused/encoder only/etc) */
VGM_ASSERT(data->codecCtx->delay > 0, "FFMPEG: delay %i\n", (int)data->codecCtx->delay);//delay: OPUS
//VGM_ASSERT(data->codecCtx->internal->skip_samples > 0, ...); /* for codec use, not accessible */
VGM_ASSERT(data->codecCtx->delay > 0, "FFMPEG: delay %i\n", (int)data->codecCtx->delay);//delay: OPUS
VGM_ASSERT(stream->codecpar->initial_padding > 0, "FFMPEG: initial_padding %i\n", (int)stream->codecpar->initial_padding);//delay: OPUS
VGM_ASSERT(stream->codecpar->trailing_padding > 0, "FFMPEG: trailing_padding %i\n", (int)stream->codecpar->trailing_padding);
VGM_ASSERT(stream->codecpar->seek_preroll > 0, "FFMPEG: seek_preroll %i\n", (int)stream->codecpar->seek_preroll);//seek delay: OPUS
VGM_ASSERT(stream->start_time > 0, "FFMPEG: start_time %i\n", (int)stream->start_time); //delay
VGM_ASSERT(stream->first_discard_sample > 0, "FFMPEG: first_discard_sample %i\n", (int)stream->first_discard_sample); //padding: MP3
VGM_ASSERT(stream->last_discard_sample > 0, "FFMPEG: last_discard_sample %i\n", (int)stream->last_discard_sample); //padding: MP3
#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 64, 100)
VGM_ASSERT(stream->skip_samples > 0, "FFMPEG: skip_samples %i\n", (int)stream->skip_samples); //delay: MP4
VGM_ASSERT(stream->start_skip_samples > 0, "FFMPEG: start_skip_samples %i\n", (int)stream->start_skip_samples); //delay: MP3
#else
VGM_ASSERT(stream->start_time > 0, "FFMPEG: start_time %i\n", (int)stream->start_time); //delay
#endif
VGM_ASSERT(stream->first_discard_sample > 0, "FFMPEG: first_discard_sample %i\n", (int)stream->first_discard_sample); //padding: MP3
VGM_ASSERT(stream->last_discard_sample > 0, "FFMPEG: last_discard_sample %i\n", (int)stream->last_discard_sample); //padding: MP3
/* also negative timestamp for formats like OGG/OPUS */
/* not using it: BINK, FLAC, ATRAC3, XMA, MPC, WMA (may use internal skip samples) */
//todo: double check Opus behavior
}
@ -398,44 +454,46 @@ static int init_ffmpeg_config(ffmpeg_codec_data* data, int target_subsong, int r
/* find valid audio stream and set other streams to discard */
{
int i, streamIndex, streamCount;
int i, stream_index, stream_count;
streamIndex = -1;
streamCount = 0;
stream_index = -1;
stream_count = 0;
if (reset)
streamIndex = data->streamIndex;
stream_index = data->stream_index;
for (i = 0; i < data->formatCtx->nb_streams; ++i) {
AVStream *stream = data->formatCtx->streams[i];
AVStream* stream = data->formatCtx->streams[i];
if (stream->codecpar && stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
streamCount++;
stream_count++;
/* select Nth audio stream if specified, or first one */
if (streamIndex < 0 || (target_subsong > 0 && streamCount == target_subsong)) {
streamIndex = i;
if (stream_index < 0 || (target_subsong > 0 && stream_count == target_subsong)) {
stream_index = i;
}
}
if (i != streamIndex)
if (i != stream_index)
stream->discard = AVDISCARD_ALL; /* disable demuxing for other streams */
}
if (streamCount < target_subsong) goto fail;
if (streamIndex < 0) goto fail;
if (stream_count < target_subsong) goto fail;
if (stream_index < 0) goto fail;
data->streamIndex = streamIndex;
data->streamCount = streamCount;
data->stream_index = stream_index;
data->stream_count = stream_count;
}
/* setup codec with stream info */
data->codecCtx = avcodec_alloc_context3(NULL);
if (!data->codecCtx) goto fail;
errcode = avcodec_parameters_to_context(data->codecCtx, ((AVStream*)data->formatCtx->streams[data->streamIndex])->codecpar);
errcode = avcodec_parameters_to_context(data->codecCtx, data->formatCtx->streams[data->stream_index]->codecpar);
if (errcode < 0) goto fail;
//av_codec_set_pkt_timebase(data->codecCtx, stream->time_base); /* deprecated and seemingly not needed */
/* deprecated and seemingly not needed */
//av_codec_set_pkt_timebase(data->codecCtx, stream->time_base);
/* not useddeprecated and seemingly not needed */
data->codec = avcodec_find_decoder(data->codecCtx->codec_id);
if (!data->codec) goto fail;
@ -501,7 +559,7 @@ static int decode_ffmpeg_frame(ffmpeg_codec_data* data) {
}
/* ignore non-selected streams */
if (data->packet->stream_index != data->streamIndex)
if (data->packet->stream_index != data->stream_index)
continue;
}
@ -788,7 +846,7 @@ void seek_ffmpeg(ffmpeg_codec_data* data, int32_t num_sample) {
if (errcode < 0) goto fail;
}
else {
avformat_seek_file(data->formatCtx, data->streamIndex, 0, 0, 0, AVSEEK_FLAG_ANY);
avformat_seek_file(data->formatCtx, data->stream_index, 0, 0, 0, AVSEEK_FLAG_ANY);
avcodec_flush_buffers(data->codecCtx);
}
@ -800,18 +858,10 @@ void seek_ffmpeg(ffmpeg_codec_data* data, int32_t num_sample) {
data->end_of_stream = 0;
data->end_of_audio = 0;
/* consider skip samples (encoder delay), if manually set (otherwise let FFmpeg handle it) */
/* consider skip samples (encoder delay), if manually set */
if (data->skip_samples_set) {
AVStream *stream = data->formatCtx->streams[data->streamIndex];
/* sometimes (ex. AAC) after seeking to the first packet skip_samples is restored, but we want our value */
#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 64, 100)
stream->skip_samples = 0;
stream->start_skip_samples = 0;
#else
stream->start_time = 0;
#endif
data->samples_discard += data->skipSamples;
data->samples_discard += data->skip_samples;
/* internally FFmpeg may skip (skip_samples/start_skip_samples) too */
}
return;
@ -872,40 +922,53 @@ void free_ffmpeg(ffmpeg_codec_data* data) {
data->header_block = NULL;
}
close_streamfile(data->streamfile);
close_streamfile(data->sf);
free(data);
}
/**
* Sets the number of samples to skip at the beginning of the stream, needed by some "gapless" formats.
* (encoder delay, usually added by MDCT-based encoders like AAC/MP3/ATRAC3/XMA/etc to "set up" the decoder).
* Sets the number of samples to skip at the beginning of the stream (encoder delay), needed by some "gapless" formats.
* - should be used at the beginning of the stream
* - should check if there are data->skipSamples before using this, to avoid overwritting FFmpeg's value (ex. AAC).
* - should use only if/when FFmpeg's format is known to botch encoder delay.
*
* This could be added per format in FFmpeg directly, but it's here for flexibility and due to bugs
* (FFmpeg's stream->(start_)skip_samples causes glitches in XMA).
* encoder delay in FFmpeg is handled in multiple ways:
* - avstream/internal->start_skip_samples: skip in the first packet *if* pts=0 (set in MP3 only?)
* - avstream/internal->skip_samples: skip in any packet (set in AAC encoded by libfaac, OPUS, MP3 in SWF, MOV/MP4)
* - avstream->start_time: usually set same as skip_samples but in pts, info only (most of the above but OPUS)
* - codecCtx->delay: seems equivalent to skip_samples, info only (OPUS)
* - negative timestamp: Xiph style (Ogg Vorbis/Opus only?).
* First two are only exposed in FFmpeg v4.4<, meaning you can't override buggy values after that.
* But since FFmpeg only does encoder delay for a handful of formats, shouldn't matter much.
* May need to detect exact versions if they start fixing formats.
*/
void ffmpeg_set_skip_samples(ffmpeg_codec_data* data, int skip_samples) {
AVStream *stream = NULL;
if (!data || !data->formatCtx)
if (!data || !data->formatCtx || !skip_samples)
return;
/* overwrite FFmpeg's skip samples */
stream = data->formatCtx->streams[data->streamIndex];
/* let FFmpeg handle (may need an option to force override?) */
if (data->skip_samples) {
VGM_ASSERT(data->skip_samples != skip_samples,
"FMPEG: ignored skip_samples %i, already set %i\n", skip_samples, (int)data->skip_samples);
return;
}
#if 0
{
AVStream* stream = data->formatCtx->streams[data->stream_index];
#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 64, 100)
stream->start_skip_samples = 0; /* used for the first packet *if* pts=0 */
stream->skip_samples = 0; /* skip_samples can be used for any packet */
stream->start_skip_samples = 0;
stream->skip_samples = 0;
#else
stream->start_time = 0;
//stream->start_time = 0; /* info only = useless */
#endif
}
#endif
/* set skip samples with our internal discard */
data->skip_samples_set = 1;
data->samples_discard = skip_samples;
/* expose (info only) */
data->skipSamples = skip_samples;
data->skip_samples = skip_samples;
}
/* returns channel layout if set */
@ -920,10 +983,10 @@ uint32_t ffmpeg_get_channel_layout(ffmpeg_codec_data* data) {
void ffmpeg_set_channel_remapping(ffmpeg_codec_data* data, int *channel_remap) {
int i;
if (data->channels > 32)
if (data->codecCtx->channels > 32)
return;
for (i = 0; i < data->channels; i++) {
for (i = 0; i < data->codecCtx->channels; i++) {
data->channel_remap[i] = channel_remap[i];
}
data->channel_remap_set = 1;
@ -940,12 +1003,20 @@ const char* ffmpeg_get_codec_name(ffmpeg_codec_data* data) {
}
void ffmpeg_set_force_seek(ffmpeg_codec_data* data) {
if (!data)
return;
/* some formats like Smacker are so buggy that any seeking is impossible (even on video players),
* or MPC with an incorrectly parsed seek table (using as 0 some non-0 seek offset).
* whatever, we'll just kill and reconstruct FFmpeg's config every time */
data->force_seek = 1;
reset_ffmpeg(data); /* reset state from trying to seek */
//stream = data->formatCtx->streams[data->streamIndex];
//stream = data->formatCtx->streams[data->stream_index];
}
void ffmpeg_set_invert_floats(ffmpeg_codec_data* data) {
if (!data)
return;
data->invert_floats_set = 1;
}
const char* ffmpeg_get_metadata_value(ffmpeg_codec_data* data, const char* key) {
@ -955,7 +1026,7 @@ const char* ffmpeg_get_metadata_value(ffmpeg_codec_data* data, const char* key)
if (!data || !data->codec)
return NULL;
avd = data->formatCtx->streams[data->streamIndex]->metadata; /* per stream (like Ogg) */
avd = data->formatCtx->streams[data->stream_index]->metadata; /* per stream (like Ogg) */
if (!avd)
avd = data->formatCtx->metadata; /* per format (like Flac) */
if (!avd)
@ -968,8 +1039,33 @@ const char* ffmpeg_get_metadata_value(ffmpeg_codec_data* data, const char* key)
return avde->value;
}
int32_t ffmpeg_get_samples(ffmpeg_codec_data* data) {
if (!data)
return 0;
return (int32_t)data->total_samples;
}
int ffmpeg_get_sample_rate(ffmpeg_codec_data* data) {
if (!data || !data->codecCtx)
return 0;
return data->codecCtx->sample_rate;
}
int ffmpeg_get_channels(ffmpeg_codec_data* data) {
if (!data || !data->codecCtx)
return 0;
return data->codecCtx->channels;
}
int ffmpeg_get_subsong_count(ffmpeg_codec_data* data) {
if (!data)
return 0;
return data->stream_count;
}
STREAMFILE* ffmpeg_get_streamfile(ffmpeg_codec_data* data) {
if (!data) return NULL;
return data->streamfile;
return data->sf;
}
#endif

View File

@ -764,10 +764,8 @@ static ffmpeg_codec_data* init_ffmpeg_custom_opus_config(STREAMFILE* sf, off_t s
/* FFmpeg + libopus: skips samples, notifies skip in codecCtx->delay (not in stream->skip_samples)
* FFmpeg + opus: *doesn't* skip, also notifies skip in codecCtx->delay, hurray (possibly fixed in recent versions)
* FFmpeg + opus is audibly buggy with some low bitrate SSB Ultimate files too */
//if (ffmpeg_data->skipSamples <= 0) {
// ffmpeg_set_skip_samples(ffmpeg_data, skip);
//}
* FFmpeg + opus is audibly buggy with some low bitrate SSB Ultimate files */
//ffmpeg_set_skip_samples(ffmpeg_data, skip);
close_streamfile(temp_sf);
return ffmpeg_data;
@ -786,7 +784,7 @@ static ffmpeg_codec_data* init_ffmpeg_custom_opus(STREAMFILE* sf, off_t start_of
return init_ffmpeg_custom_opus_config(sf, start_offset, data_size, &cfg, type);
}
ffmpeg_codec_data* init_ffmpeg_custom_table_opus(STREAMFILE* sf, off_t table_offset, int table_count, off_t data_offset, size_t data_size, int channels, int skip, int sample_rate, opus_type_t type) {
static ffmpeg_codec_data* init_ffmpeg_custom_table_opus(STREAMFILE* sf, off_t table_offset, int table_count, off_t data_offset, size_t data_size, int channels, int skip, int sample_rate, opus_type_t type) {
opus_config cfg = {0};
cfg.channels = channels;
cfg.skip = skip;

View File

@ -2,7 +2,7 @@
#ifdef VGM_USE_FFMPEG
static int ffmpeg_make_riff_atrac3(uint8_t * buf, size_t buf_size, size_t sample_count, size_t data_size, int channels, int sample_rate, int block_align, int joint_stereo, int encoder_delay) {
static int ffmpeg_make_riff_atrac3(uint8_t* buf, size_t buf_size, size_t sample_count, size_t data_size, int channels, int sample_rate, int block_align, int joint_stereo, int encoder_delay) {
uint16_t codec_ATRAC3 = 0x0270;
size_t riff_size = 4+4+ 4 + 0x28 + 0x10 + 4+4;
@ -41,7 +41,7 @@ static int ffmpeg_make_riff_atrac3(uint8_t * buf, size_t buf_size, size_t sample
return riff_size;
}
ffmpeg_codec_data * init_ffmpeg_atrac3_raw(STREAMFILE *sf, off_t offset, size_t data_size, int sample_count, int channels, int sample_rate, int block_align, int encoder_delay) {
ffmpeg_codec_data* init_ffmpeg_atrac3_raw(STREAMFILE* sf, off_t offset, size_t data_size, int sample_count, int channels, int sample_rate, int block_align, int encoder_delay) {
ffmpeg_codec_data *ffmpeg_data = NULL;
uint8_t buf[0x100];
int bytes;
@ -57,16 +57,14 @@ ffmpeg_codec_data * init_ffmpeg_atrac3_raw(STREAMFILE *sf, off_t offset, size_t
* in offsets, so calcs are expected to be handled externally (presumably the game would call raw decoding API
* and any skips would be handled manually) */
/* FFmpeg reads this but just in case they fiddle with it in the future */
ffmpeg_data->totalSamples = sample_count;
/* encoder delay: encoder introduces some garbage (not always silent) samples to skip at the beginning (at least 1 frame)
* FFmpeg doesn't set this, and even if it ever does it's probably better to force it for the implicit skip. */
ffmpeg_set_skip_samples(ffmpeg_data, encoder_delay);
//ffmpeg_set_samples(sample_count); /* useful? */
/* invert ATRAC3: waveform is inverted vs official tools (not noticeable but for accuracy) */
if (is_at3) {
ffmpeg_data->invert_floats_set = 1;
ffmpeg_set_invert_floats(ffmpeg_data);
}
return ffmpeg_data;
@ -76,7 +74,7 @@ fail:
}
/* init ATRAC3/plus while adding some fixes */
ffmpeg_codec_data * init_ffmpeg_atrac3_riff(STREAMFILE *sf, off_t offset, int* out_samples) {
ffmpeg_codec_data* init_ffmpeg_atrac3_riff(STREAMFILE* sf, off_t offset, int* p_samples) {
ffmpeg_codec_data *ffmpeg_data = NULL;
int is_at3 = 0, is_at3p = 0, codec;
size_t riff_size;
@ -151,35 +149,33 @@ ffmpeg_codec_data * init_ffmpeg_atrac3_riff(STREAMFILE *sf, off_t offset, int* o
implicit_skip = 0;
}
/* FFmpeg reads this but just in case they fiddle with it in the future */
ffmpeg_data->totalSamples = fact_samples;
/* encoder delay: encoder introduces some garbage (not always silent) samples to skip at the beginning (at least 1 frame)
* FFmpeg doesn't set this, and even if it ever does it's probably better to force it for the implicit skip. */
ffmpeg_set_skip_samples(ffmpeg_data, skip_samples + implicit_skip);
//ffmpeg_set_samples(sample_count); /* useful? */
/* invert ATRAC3: waveform is inverted vs official tools (not noticeable but for accuracy) */
if (is_at3) {
ffmpeg_data->invert_floats_set = 1;
ffmpeg_set_invert_floats(ffmpeg_data);
}
/* multichannel fix: LFE channel should be reordered on decode (ATRAC3Plus only, only 1/2/6/8ch exist):
* - 6ch: FL FR FC BL BR LFE > FL FR FC LFE BL BR
* - 8ch: FL FR FC BL BR SL SR LFE > FL FR FC LFE BL BR SL SR */
if (is_at3p && ffmpeg_data->channels == 6) {
if (is_at3p && ffmpeg_get_channels(ffmpeg_data) == 6) {
/* LFE BR BL > LFE BL BR > same */
int channel_remap[] = { 0, 1, 2, 5, 5, 5, };
ffmpeg_set_channel_remapping(ffmpeg_data, channel_remap);
}
else if (is_at3p && ffmpeg_data->channels == 8) {
else if (is_at3p && ffmpeg_get_channels(ffmpeg_data) == 8) {
/* LFE BR SL SR BL > LFE BL SL SR BR > LFE BL BR SR SL > LFE BL BR SL SR > same */
int channel_remap[] = { 0, 1, 2, 7, 7, 7, 7, 7};
ffmpeg_set_channel_remapping(ffmpeg_data, channel_remap);
}
if (out_samples)
*out_samples = fact_samples;
if (p_samples)
*p_samples = fact_samples;
return ffmpeg_data;
fail:
@ -187,7 +183,7 @@ fail:
return NULL;
}
ffmpeg_codec_data* init_ffmpeg_aac(STREAMFILE* sf, off_t offset, size_t size) {
ffmpeg_codec_data* init_ffmpeg_aac(STREAMFILE* sf, off_t offset, size_t size, int skip_samples) {
ffmpeg_codec_data* data = NULL;
data = init_ffmpeg_offset(sf, offset, size);
@ -199,7 +195,7 @@ ffmpeg_codec_data* init_ffmpeg_aac(STREAMFILE* sf, off_t offset, size_t size) {
/* raw AAC doesn't set this, while some decoders like FAAD remove 1024,
* but should be handled in container as each encoder uses its own value
* (Apple: 2112, FAAD: probably 1024, etc) */
//ffmpeg_set_skip_samples(data, 1024);
ffmpeg_set_skip_samples(data, skip_samples);
return data;
fail:

View File

@ -302,7 +302,7 @@ static void aes_decrypt_block(s14aes_handle* ctx, uint8_t* buf) {
/* **************************** */
s14aes_handle* s14aes_init() {
s14aes_handle* s14aes_init(void) {
s14aes_handle* ctx = malloc(sizeof(s14aes_handle));
if (!ctx) goto fail;

View File

@ -6,7 +6,7 @@
typedef struct s14aes_handle s14aes_handle;
/* init/close handle (AES-192 in ECB mode) */
s14aes_handle* s14aes_init();
s14aes_handle* s14aes_init(void);
void s14aes_close(s14aes_handle* ctx);

View File

@ -1,4 +1,5 @@
#include "coding.h"
#include "clHCA.h"
struct hca_codec_data {

View File

@ -983,7 +983,7 @@ void decode_fsb_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t *
}
/* mono XBOX-IMA with header endianness and alt nibble expand (verified vs AK test demos) */
void decode_wwise_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
void decode_wwise_ima(VGMSTREAM* vgmstream, VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i, sample_count = 0, num_frame;
int32_t hist1 = stream->adpcm_history1_32;
int step_index = stream->adpcm_step_index;
@ -1242,7 +1242,7 @@ static inline int _clamp_s32(int value, int min, int max) {
/* Crystal Dynamics IMA. Original code uses mind-bending intrinsics, so this may not be fully accurate.
* Has another table with delta_table MMX combos, and uses header sample (first nibble is always 0). */
void decode_cd_ima(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
void decode_cd_ima(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
uint8_t frame[0x24] = {0};
int i, frames_in, sample_pos = 0, block_samples, frame_size;
int32_t hist1 = stream->adpcm_history1_32;

View File

@ -309,7 +309,7 @@ fail:
/* **************************************** */
static void decode_vima1(STREAMFILE* sf, sbuf_t* sbuf, uint8_t* buf, size_t data_left, int block_num, uint16_t* adpcm_table) {
static void decode_vima1(sbuf_t* sbuf, uint8_t* buf, size_t data_left, int block_num, uint16_t* adpcm_table) {
int ch, i, j, s;
int bitpos;
int adpcm_history[MAX_CHANNELS] = {0};
@ -420,13 +420,13 @@ static void decode_vima1(STREAMFILE* sf, sbuf_t* sbuf, uint8_t* buf, size_t data
sbuf->filled += data_left / sizeof(int16_t) / chs;
}
static int decode_block1(STREAMFILE* sf, imuse_codec_data* data, uint8_t* block, size_t data_left) {
static int decode_block1(imuse_codec_data* data, uint8_t* block, size_t data_left) {
int block_num = data->current_block;
switch(data->block_table[block_num].flags) {
case 0x0D:
case 0x0F:
decode_vima1(sf, &data->sbuf, block, data_left, block_num, data->adpcm_table);
decode_vima1(&data->sbuf, block, data_left, block_num, data->adpcm_table);
break;
default:
return 0;
@ -434,7 +434,7 @@ static int decode_block1(STREAMFILE* sf, imuse_codec_data* data, uint8_t* block,
return 1;
}
static void decode_data2(STREAMFILE* sf, sbuf_t* sbuf, uint8_t* buf, size_t data_left, int block_num) {
static void decode_data2(sbuf_t* sbuf, uint8_t* buf, size_t data_left, int block_num) {
int i, j;
int channels = sbuf->channels;
@ -453,7 +453,7 @@ static void decode_data2(STREAMFILE* sf, sbuf_t* sbuf, uint8_t* buf, size_t data
}
}
static void decode_vima2(STREAMFILE* sf, sbuf_t* sbuf, uint8_t* buf, size_t data_left, uint16_t* adpcm_table) {
static void decode_vima2(sbuf_t* sbuf, uint8_t* buf, size_t data_left, uint16_t* adpcm_table) {
int ch, i, s;
int bitpos;
int adpcm_history[MAX_CHANNELS] = {0};
@ -554,16 +554,16 @@ static void decode_vima2(STREAMFILE* sf, sbuf_t* sbuf, uint8_t* buf, size_t data
sbuf->filled += data_left / sizeof(int16_t) / chs;
}
static int decode_block2(STREAMFILE* sf, imuse_codec_data* data, uint8_t* block, size_t data_left) {
static int decode_block2(imuse_codec_data* data, uint8_t* block, size_t data_left) {
int block_num = data->current_block;
switch(data->block_table[block_num].flags) {
case 0x00:
decode_data2(sf, &data->sbuf, block, data_left, block_num);
decode_data2(&data->sbuf, block, data_left, block_num);
break;
case 0x01:
decode_vima2(sf, &data->sbuf, block, data_left, data->adpcm_table);
decode_vima2(&data->sbuf, block, data_left, data->adpcm_table);
break;
default:
return 0;
@ -597,11 +597,11 @@ static int decode_block(STREAMFILE* sf, imuse_codec_data* data) {
switch(data->type) {
case COMP:
ok = decode_block1(sf, data, block, data_left);
ok = decode_block1(data, block, data_left);
break;
case MCMP:
ok = decode_block2(sf, data, block, data_left);
ok = decode_block2(data, block, data_left);
break;
default:

View File

@ -3,13 +3,12 @@
#include "../vgmstream.h"
#ifdef VGM_USE_MPEG
#include <mpg123/mpg123.h>
#include "mpeg_decoder.h"
#define MPEG_DATA_BUFFER_SIZE 0x1000 /* at least one MPEG frame (max ~0x5A1 plus some more in case of free bitrate) */
static mpg123_handle* init_mpg123_handle();
static mpg123_handle* init_mpg123_handle(void);
static void decode_mpeg_standard(VGMSTREAMCHANNEL* stream, mpeg_codec_data* data, sample_t* outbuf, int32_t samples_to_do, int channels);
static void decode_mpeg_custom(VGMSTREAM* vgmstream, mpeg_codec_data* data, sample_t* outbuf, int32_t samples_to_do, int channels);
static void decode_mpeg_custom_stream(VGMSTREAMCHANNEL *stream, mpeg_codec_data* data, int num_stream);
@ -185,7 +184,7 @@ fail:
}
static mpg123_handle* init_mpg123_handle() {
static mpg123_handle* init_mpg123_handle(void) {
mpg123_handle* m = NULL;
int rc;

View File

@ -1,5 +1,6 @@
#ifndef _MPEG_DECODER_H_
#define _MPEG_DECODER_H_
#include <mpg123/mpg123.h>
#include "../vgmstream.h"
#include "../coding/coding.h"

View File

@ -0,0 +1,63 @@
#include "coding.h"
/* Decodes Tantalus TADC ADPCM codec, used in Saturn games.
* Guessed based on other XA-style codecs values. */
void decode_tantalus(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
uint8_t frame[0x10] = {0};
off_t frame_offset;
int i, frames_in, sample_count = 0;
size_t bytes_per_frame, samples_per_frame;
int shift, filter, coef1, coef2;
int32_t hist1 = stream->adpcm_history1_32;
int32_t hist2 = stream->adpcm_history2_32;
/* external interleave (fixed size), mono */
bytes_per_frame = 0x10;
samples_per_frame = (bytes_per_frame - 0x01) * 2;
frames_in = first_sample / samples_per_frame;
//first_sample = first_sample % samples_per_frame; /* for flat layout */
/* parse frame header */
frame_offset = stream->offset + bytes_per_frame*frames_in;
read_streamfile(frame, frame_offset, bytes_per_frame, stream->streamfile); /* ignore EOF errors */
filter = (frame[0x00] >> 4) & 0xf; /* 0 in tested files */
shift = (frame[0x00] >> 0) & 0xf;
if (filter != 0) {
VGM_LOG_ONCE("TANTALUS: unknown filter\n");
coef1 = 64;
coef2 = 64; /* will sound horrid and hopefully reported */
}
else {
coef1 = 64;
coef2 = 0;
}
/* decode nibbles */
for (i = first_sample; i < first_sample + samples_to_do; i++) {
uint8_t nibbles = frame[0x01 + i/2];
int32_t sample;
sample = i&1 ? /* low nibble first */
get_high_nibble_signed(nibbles) :
get_low_nibble_signed(nibbles);
sample = sample << (shift + 6);
sample = (sample + (hist1 * coef1) + (hist2 * coef2)) >> 6;
outbuf[sample_count] = clamp16(sample);
sample_count += channelspacing;
hist2 = hist1;
hist1 = sample;
}
stream->adpcm_history1_32 = hist1;
stream->adpcm_history2_32 = hist2;
}
int32_t tantalus_bytes_to_samples(size_t bytes, int channels) {
if (channels <= 0) return 0;
return bytes / channels / 0x10 * 30;
}

View File

@ -455,7 +455,7 @@ static void decode_subframe_stereo(ubi_adpcm_channel_data* ch0_state, ubi_adpcm_
* 0xA82557DB LE = 1010 100000 100101 010101 111101 1011 ... (where last 00 | first 1010 = 001010), etc
* Codes aren't signed but rather have a particular meaning (see decoding).
*/
void unpack_codes(uint8_t* data, uint8_t* codes, int code_count, int bps) {
static void unpack_codes(uint8_t* data, uint8_t* codes, int code_count, int bps) {
int i;
size_t pos = 0;
uint64_t bits = 0, input = 0;

View File

@ -3,7 +3,6 @@
#include "vorbis_custom_decoder.h"
#ifdef VGM_USE_VORBIS
#include <vorbis/codec.h>
#define VORBIS_DEFAULT_BUFFER_SIZE 0x8000 /* should be at least the size of the setup header, ~0x2000 */

View File

@ -6,6 +6,7 @@
/* used by vorbis_custom_decoder.c, but scattered in other .c files */
#ifdef VGM_USE_VORBIS
#include <vorbis/codec.h>
/* custom Vorbis without Ogg layer */
struct vorbis_custom_codec_data {

View File

@ -77,7 +77,7 @@ int vorbis_custom_parse_packet_vid1(VGMSTREAMCHANNEL* stream, vorbis_custom_code
/* get packet info the VID1 header */
get_packet_header(stream->streamfile, &stream->offset, (uint32_t*)&data->op.bytes);
get_packet_header(stream->streamfile, &stream->offset, (size_t*)&data->op.bytes);
if (data->op.bytes == 0 || data->op.bytes > data->buffer_size) goto fail; /* EOF or end padding */
/* read raw block */

View File

@ -365,11 +365,6 @@ static int ww2ogg_generate_vorbis_packet(bitstream_t* ow, bitstream_t* iw, wpack
/* rebuild first bits of packet type and window info (for the i-MDCT) */
uint32_t packet_type = 0, mode_number = 0, remainder = 0;
if (!data->mode_blockflag) { /* config error */
VGM_LOG("Wwise Vorbis: didn't load mode_blockflag\n");
goto fail;
}
/* audio packet type */
packet_type = 0;
wv_bits(ow, 1, packet_type);
@ -434,8 +429,8 @@ static int ww2ogg_generate_vorbis_packet(bitstream_t* ow, bitstream_t* iw, wpack
return 1;
fail:
return 0;
//fail:
// return 0;
}
/*******************************************************************************/

View File

@ -135,6 +135,8 @@ void decode_ws(VGMSTREAM * vgmstream, int channel, sample * outbuf, int channels
samples_left_in_frame--) { /* done with reading a sample */
outbuf[sample_count]=(hist-0x80)*0x100;
}
default:
break;
}
}
}

View File

@ -503,6 +503,8 @@ int get_vgmstream_samples_per_frame(VGMSTREAM* vgmstream) {
return 256; /* (0x8c - 0xc) * 2 */
case coding_ASF:
return 32; /* (0x11 - 0x1) * 2 */
case coding_TANTALUS:
return 30; /* (0x10 - 0x01) * 2 */
case coding_DSA:
return 14; /* (0x08 - 0x1) * 2 */
case coding_XMD:
@ -716,6 +718,8 @@ int get_vgmstream_frame_size(VGMSTREAM* vgmstream) {
return 0x8c;
case coding_ASF:
return 0x11;
case coding_TANTALUS:
return 0x10;
case coding_DSA:
return 0x08;
case coding_XMD:
@ -1008,7 +1012,7 @@ void decode_vgmstream(VGMSTREAM* vgmstream, int samples_written, int samples_to_
case coding_EA_XA_V2:
for (ch = 0; ch < vgmstream->channels; ch++) {
decode_ea_xa_v2(&vgmstream->ch[ch], buffer+ch,
vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch);
vgmstream->channels, vgmstream->samples_into_block, samples_to_do);
}
break;
case coding_MAXIS_XA:
@ -1020,7 +1024,7 @@ void decode_vgmstream(VGMSTREAM* vgmstream, int samples_written, int samples_to_
case coding_EA_XAS_V0:
for (ch = 0; ch < vgmstream->channels; ch++) {
decode_ea_xas_v0(&vgmstream->ch[ch], buffer+ch,
vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch);
vgmstream->channels, vgmstream->samples_into_block, samples_to_do);
}
break;
case coding_EA_XAS_V1:
@ -1184,7 +1188,7 @@ void decode_vgmstream(VGMSTREAM* vgmstream, int samples_written, int samples_to_
case coding_WWISE_IMA:
for (ch = 0; ch < vgmstream->channels; ch++) {
decode_wwise_ima(vgmstream,&vgmstream->ch[ch], buffer+ch,
vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch);
vgmstream->channels, vgmstream->samples_into_block, samples_to_do);
}
break;
case coding_REF_IMA:
@ -1223,7 +1227,7 @@ void decode_vgmstream(VGMSTREAM* vgmstream, int samples_written, int samples_to_
case coding_CD_IMA:
for (ch = 0; ch < vgmstream->channels; ch++) {
decode_cd_ima(&vgmstream->ch[ch], buffer+ch,
vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch);
vgmstream->channels, vgmstream->samples_into_block, samples_to_do);
}
break;
@ -1386,6 +1390,12 @@ void decode_vgmstream(VGMSTREAM* vgmstream, int samples_written, int samples_to_
vgmstream->channels, vgmstream->samples_into_block, samples_to_do);
}
break;
case coding_TANTALUS:
for (ch = 0; ch < vgmstream->channels; ch++) {
decode_tantalus(&vgmstream->ch[ch], buffer+ch,
vgmstream->channels, vgmstream->samples_into_block, samples_to_do);
}
break;
case coding_DSA:
for (ch = 0; ch < vgmstream->channels; ch++) {
decode_dsa(&vgmstream->ch[ch], buffer+ch,

View File

@ -515,6 +515,7 @@ static const char* extension_list[] = {
"sxd2",
"sxd3",
"tad",
"tec",
"tgq",
"thp",
@ -787,6 +788,7 @@ static const coding_info coding_info_list[] = {
{coding_MC3, "Paradigm MC3 3-bit ADPCM"},
{coding_FADPCM, "FMOD FADPCM 4-bit ADPCM"},
{coding_ASF, "Argonaut ASF 4-bit ADPCM"},
{coding_TANTALUS, "Tantalus 4-bit ADPCM"},
{coding_DSA, "Ocean DSA 4-bit ADPCM"},
{coding_XMD, "Konami XMD 4-bit ADPCM"},
{coding_PCFX, "PC-FX 4-bit ADPCM"},
@ -997,7 +999,7 @@ static const meta_info meta_info_list[] = {
{meta_LEG, "Legaia 2 - Duel Saga LEG Header"},
{meta_FILP, "Bio Hazard - Gun Survivor FILp Header"},
{meta_IKM, "MiCROViSiON IKM header"},
{meta_SFS, "Baroque SFS Header"},
{meta_SFS, "String .SFS header"},
{meta_SAT_DVI, "Konami KCEN DVI. header"},
{meta_DC_KCEY, "Konami KCEY KCEYCOMP header"},
{meta_BG00, "Falcom BG00 Header"},
@ -1350,6 +1352,7 @@ static const meta_info meta_info_list[] = {
{meta_IDSP_TOSE, "TOSE .IDSP header"},
{meta_DSP_KWA, "Kuju London .KWA header"},
{meta_OGV_3RDEYE, "3rdEye .OGV header"},
{meta_PIFF_TPCM, "Tantalus PIFF TPCM header"},
};
void get_vgmstream_coding_description(VGMSTREAM* vgmstream, char* out, size_t out_size) {

View File

@ -4,7 +4,7 @@
#include "../vgmstream.h"
static size_t get_channel_header_size(STREAMFILE* sf, off_t offset, int channels, int big_endian);
static size_t get_channel_header_size(STREAMFILE* sf, off_t offset, int big_endian);
static size_t get_block_header_size(STREAMFILE* sf, off_t offset, size_t channel_header_size, int channels, int big_endian);
/* AWC music chunks */
@ -38,7 +38,7 @@ void block_update_awc(off_t block_offset, VGMSTREAM * vgmstream) {
* 32b * entries = global samples per frame in each block (for MPEG probably per full frame)
*/
channel_header_size = get_channel_header_size(sf, block_offset, vgmstream->channels, vgmstream->codec_endian);
channel_header_size = get_channel_header_size(sf, block_offset, vgmstream->codec_endian);
header_size = get_block_header_size(sf, block_offset, channel_header_size, vgmstream->channels, vgmstream->codec_endian);
for (i = 0; i < vgmstream->channels; i++) {
vgmstream->ch[i].offset = block_offset + header_size + 0x800*entries*i;
@ -47,7 +47,7 @@ void block_update_awc(off_t block_offset, VGMSTREAM * vgmstream) {
}
static size_t get_channel_header_size(STREAMFILE* sf, off_t offset, int channels, int big_endian) {
static size_t get_channel_header_size(STREAMFILE* sf, off_t offset, int big_endian) {
int32_t (*read_32bit)(off_t,STREAMFILE*) = big_endian ? read_32bitBE : read_32bitLE;
/* later games have an smaller channel header, try to detect using

View File

@ -1,19 +1,19 @@
#include "layout.h"
#include "../coding/coding.h"
#include "../vgmstream.h"
/* XVAG with subsongs layers, interleaves chunks of each subsong (a hack to support them) */
void block_update_xvag_subsong(off_t block_offset, VGMSTREAM * vgmstream) {
int i;
size_t channel_size = 0x10;
/* set offsets */
for (i = 0; i < vgmstream->channels; i++) {
vgmstream->ch[i].offset = block_offset + channel_size*i;
}
//vgmstream->current_block_size = ; /* fixed */
vgmstream->current_block_offset = block_offset;
vgmstream->next_block_offset = block_offset + vgmstream->full_block_size;
}
#include "layout.h"
#include "../coding/coding.h"
#include "../vgmstream.h"
/* XVAG with subsongs layers, interleaves chunks of each subsong (a hack to support them) */
void block_update_xvag_subsong(off_t block_offset, VGMSTREAM* vgmstream) {
int i;
size_t channel_size = 0x10;
/* set offsets */
for (i = 0; i < vgmstream->channels; i++) {
vgmstream->ch[i].offset = block_offset + channel_size*i;
}
//vgmstream->current_block_size = ; /* fixed */
vgmstream->current_block_offset = block_offset;
vgmstream->next_block_offset = block_offset + vgmstream->full_block_size;
}

View File

@ -240,6 +240,7 @@ VGMSTREAM* allocate_layered_vgmstream(layered_layout_data* data) {
int i, channels, loop_flag, sample_rate, external_looping;
int32_t num_samples, loop_start, loop_end;
int delta = 1024;
coding_t coding_type = data->layers[0]->coding_type;
/* get data */
channels = data->output_channels;
@ -250,6 +251,7 @@ VGMSTREAM* allocate_layered_vgmstream(layered_layout_data* data) {
loop_end = data->layers[0]->loop_end_sample;
external_looping = 0;
sample_rate = 0;
for (i = 0; i < data->layer_count; i++) {
int32_t layer_samples = vgmstream_get_samples(data->layers[i]);
int layer_loop = data->layers[i]->loop_flag;
@ -280,6 +282,9 @@ VGMSTREAM* allocate_layered_vgmstream(layered_layout_data* data) {
if (sample_rate < layer_rate)
sample_rate = layer_rate;
if (coding_type == coding_SILENCE)
coding_type = data->layers[i]->coding_type;
}
data->external_looping = external_looping;
@ -289,12 +294,12 @@ VGMSTREAM* allocate_layered_vgmstream(layered_layout_data* data) {
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = data->layers[0]->meta_type;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = num_samples;
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = loop_end;
vgmstream->meta_type = data->layers[0]->meta_type; /* info */
vgmstream->coding_type = data->layers[0]->coding_type; /* info */
vgmstream->coding_type = coding_type;
vgmstream->layout_type = layout_layered;
vgmstream->layout_data = data;

View File

@ -296,6 +296,7 @@ VGMSTREAM* allocate_segmented_vgmstream(segmented_layout_data* data, int loop_fl
int channel_layout;
int i, sample_rate;
int32_t num_samples, loop_start, loop_end;
coding_t coding_type = data->segments[0]->coding_type;
/* save data */
channel_layout = data->segments[0]->channel_layout;
@ -322,10 +323,14 @@ VGMSTREAM* allocate_segmented_vgmstream(segmented_layout_data* data, int loop_fl
if (sample_rate < segment_rate)
sample_rate = segment_rate;
if (coding_type == coding_SILENCE)
coding_type = data->segments[i]->coding_type;
}
/* respect loop_flag even when no loop_end found as it's possible file loops are set outside */
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(data->output_channels, loop_flag);
if (!vgmstream) goto fail;
@ -335,7 +340,7 @@ VGMSTREAM* allocate_segmented_vgmstream(segmented_layout_data* data, int loop_fl
vgmstream->num_samples = num_samples;
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = loop_end;
vgmstream->coding_type = data->segments[0]->coding_type;
vgmstream->coding_type = coding_type;
vgmstream->channel_layout = channel_layout;
vgmstream->layout_type = layout_segmented;

View File

@ -1,48 +1,47 @@
#include "meta.h"
#include "../coding/coding.h"
/* .208 - from Ocean game(s?) [Last Rites (PC)] */
VGMSTREAM * init_vgmstream_208(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count, sample_rate;
size_t data_size;
/* checks */
if (!check_extensions(streamFile, "208"))
goto fail;
/* possible validation: (0x04 == 0 and 0xcc == 0x1F7D984D) or 0x04 == 0xf0 and 0xcc == 0) */
if (!((read_32bitLE(0x04,streamFile) == 0x00 && read_32bitBE(0xcc,streamFile) == 0x1F7D984D) ||
(read_32bitLE(0x04,streamFile) == 0xF0 && read_32bitBE(0xcc,streamFile) == 0x00000000)))
goto fail;
start_offset = read_32bitLE(0x00,streamFile);
data_size = read_32bitLE(0x0c,streamFile);
sample_rate = read_32bitLE(0x34,streamFile);
channel_count = read_32bitLE(0x3C,streamFile); /* assumed */
loop_flag = 0;
if (start_offset + data_size != get_streamfile_size(streamFile))
goto fail;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_208;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = pcm_bytes_to_samples(data_size, channel_count, 8);
vgmstream->coding_type = coding_PCM8_U;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x1;
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
#include "meta.h"
#include "../coding/coding.h"
/* .208 - from Ocean game(s?) [Last Rites (PC)] */
VGMSTREAM* init_vgmstream_208(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset, data_size;
int loop_flag, channels, sample_rate;
/* checks */
if (!check_extensions(sf, "208"))
goto fail;
/* possible validation: (0x04 == 0 and 0xcc == 0x1F7D984D) or 0x04 == 0xf0 and 0xcc == 0) */
if (!((read_u32le(0x04,sf) == 0x00 && read_u32be(0xcc,sf) == 0x1F7D984D) ||
(read_u32le(0x04,sf) == 0xF0 && read_u32be(0xcc,sf) == 0x00000000)))
goto fail;
start_offset = read_s32le(0x00,sf);
data_size = read_s32le(0x0c,sf);
sample_rate = read_s32le(0x34,sf);
channels = read_s32le(0x3C,sf); /* assumed */
loop_flag = 0;
if (start_offset + data_size != get_streamfile_size(sf))
goto fail;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_208;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = pcm8_bytes_to_samples(data_size, channels);
vgmstream->coding_type = coding_PCM8_U;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x1;
if (!vgmstream_open_stream(vgmstream,sf,start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -91,7 +91,7 @@ fail:
#define ACB_MAX_NAME 1024 /* even more is possible in rare cases [Senran Kagura Burst Re:Newal (PC)] */
STREAMFILE* setup_acb_streamfile(STREAMFILE* sf, size_t buffer_size) {
static STREAMFILE* setup_acb_streamfile(STREAMFILE* sf, size_t buffer_size) {
STREAMFILE* new_sf = NULL;
/* buffer seems better than reopening when opening multiple subsongs at the same time with STDIO,

View File

@ -274,7 +274,7 @@ static int find_adx_key(STREAMFILE* sf, uint8_t type, uint16_t *xor_start, uint1
key_size = read_key_file(keybuf, sizeof(keybuf), sf);
if (key_size > 0) {
int i, is_ascii = 0;
int is_ascii = 0;
/* keystrings should be ASCII, also needed to tell apart 0x06 strings from derived keys */
if (type == 8) {

View File

@ -1,51 +1,51 @@
#include "meta.h"
#include "../coding/coding.h"
/* .AIF - from Asobo Studio games [Ratatouille (PC), WALL-E (PC), Up (PC)] */
VGMSTREAM * init_vgmstream_aif_asobo(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
size_t data_size;
int loop_flag, channel_count;
/* checks */
/* aif: standard, .laif/aiffl: for plugins */
if ( !check_extensions(streamFile,"aif,laif,aiffl") )
goto fail;
if ((uint16_t)read_16bitLE(0x00,streamFile) != 0x69) /* Xbox codec */
goto fail;
channel_count = read_16bitLE(0x02,streamFile); /* assumed, only stereo is known */
if (channel_count != 2) goto fail;
/* 0x08: ? */
if ((uint16_t)read_16bitLE(0x0c,streamFile) != 0x24*channel_count) /* Xbox block */
goto fail;
if ((uint16_t)read_16bitLE(0x0e,streamFile) != 0x04) /* Xbox bps */
goto fail;
loop_flag = 0;
start_offset = 0x14;
data_size = get_streamfile_size(streamFile) - start_offset;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_AIF_ASOBO;
vgmstream->sample_rate = read_32bitLE(0x04,streamFile);
vgmstream->num_samples = xbox_ima_bytes_to_samples(data_size,channel_count);
vgmstream->coding_type = coding_XBOX_IMA;
vgmstream->layout_type = layout_none;
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
#include "meta.h"
#include "../coding/coding.h"
/* .AIF - from Asobo Studio games [Ratatouille (PC), WALL-E (PC), Up (PC)] */
VGMSTREAM* init_vgmstream_aif_asobo(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
size_t data_size;
int loop_flag, channel_count;
/* checks */
/* aif: standard, .laif/aiffl: for plugins */
if ( !check_extensions(sf,"aif,laif,aiffl") )
goto fail;
if ((uint16_t)read_16bitLE(0x00,sf) != 0x69) /* Xbox codec */
goto fail;
channel_count = read_16bitLE(0x02,sf); /* assumed, only stereo is known */
if (channel_count != 2) goto fail;
/* 0x08: ? */
if ((uint16_t)read_16bitLE(0x0c,sf) != 0x24*channel_count) /* Xbox block */
goto fail;
if ((uint16_t)read_16bitLE(0x0e,sf) != 0x04) /* Xbox bps */
goto fail;
loop_flag = 0;
start_offset = 0x14;
data_size = get_streamfile_size(sf) - start_offset;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_AIF_ASOBO;
vgmstream->sample_rate = read_32bitLE(0x04,sf);
vgmstream->num_samples = xbox_ima_bytes_to_samples(data_size,channel_count);
vgmstream->coding_type = coding_XBOX_IMA;
vgmstream->layout_type = layout_none;
if ( !vgmstream_open_stream(vgmstream, sf, start_offset) )
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -3,20 +3,20 @@
#if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC)
/* AKB (AAC only) - found in SQEX iOS games */
VGMSTREAM * init_vgmstream_akb_mp4(STREAMFILE *streamFile) {
VGMSTREAM * init_vgmstream_akb_mp4(STREAMFILE *sf) {
VGMSTREAM * vgmstream = NULL;
size_t filesize;
uint32_t loop_start, loop_end;
if ((uint32_t)read_32bitBE(0, streamFile) != 0x414b4220) goto fail;
if ((uint32_t)read_32bitBE(0, sf) != 0x414b4220) goto fail;
loop_start = read_32bitLE(0x14, streamFile);
loop_end = read_32bitLE(0x18, streamFile);
loop_start = read_32bitLE(0x14, sf);
loop_end = read_32bitLE(0x18, sf);
filesize = get_streamfile_size( streamFile );
filesize = get_streamfile_size( sf );
vgmstream = init_vgmstream_mp4_aac_offset( streamFile, 0x20, filesize - 0x20 );
vgmstream = init_vgmstream_mp4_aac_offset( sf, 0x20, filesize - 0x20 );
if ( !vgmstream ) goto fail;
if ( loop_start || loop_end ) {
@ -34,7 +34,7 @@ fail:
/* AKB - found in SQEX iOS games */
VGMSTREAM * init_vgmstream_akb(STREAMFILE *streamFile) {
VGMSTREAM * init_vgmstream_akb(STREAMFILE *sf) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset, extradata_offset = 0;
size_t stream_size, header_size, subheader_size = 0, extradata_size = 0;
@ -44,28 +44,28 @@ VGMSTREAM * init_vgmstream_akb(STREAMFILE *streamFile) {
/* checks */
/* .akb.bytes is the usual extension in later games */
if ( !check_extensions(streamFile, "akb,bytes") )
if ( !check_extensions(sf, "akb,bytes") )
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x414B4220) /* "AKB " */
if (read_32bitBE(0x00,sf) != 0x414B4220) /* "AKB " */
goto fail;
if (read_32bitLE(0x08,streamFile) != get_streamfile_size(streamFile))
if (read_32bitLE(0x08,sf) != get_streamfile_size(sf))
goto fail;
/* 0x04(1): version */
header_size = read_16bitLE(0x06,streamFile);
header_size = read_16bitLE(0x06,sf);
codec = read_8bit(0x0c,streamFile);
channel_count = read_8bit(0x0d,streamFile);
sample_rate = (uint16_t)read_16bitLE(0x0e,streamFile);
num_samples = read_32bitLE(0x10,streamFile);
loop_start = read_32bitLE(0x14,streamFile);
loop_end = read_32bitLE(0x18,streamFile);
codec = read_8bit(0x0c,sf);
channel_count = read_8bit(0x0d,sf);
sample_rate = (uint16_t)read_16bitLE(0x0e,sf);
num_samples = read_32bitLE(0x10,sf);
loop_start = read_32bitLE(0x14,sf);
loop_end = read_32bitLE(0x18,sf);
/* possibly more complex, see AKB2 */
if (header_size >= 0x44) { /* v2+ */
extradata_size = read_16bitLE(0x1c,streamFile);
extradata_size = read_16bitLE(0x1c,sf);
/* 0x20+: config? (pan, volume) */
subheader_size = read_16bitLE(0x28,streamFile);
subheader_size = read_16bitLE(0x28,sf);
/* 0x24: file_id? */
/* 0x2b: encryption bitflag if version > 2? */
extradata_offset = header_size + subheader_size;
@ -75,7 +75,7 @@ VGMSTREAM * init_vgmstream_akb(STREAMFILE *streamFile) {
start_offset = header_size;
}
stream_size = get_streamfile_size(streamFile) - start_offset;
stream_size = get_streamfile_size(sf) - start_offset;
loop_flag = (loop_end > loop_start);
@ -91,14 +91,14 @@ VGMSTREAM * init_vgmstream_akb(STREAMFILE *streamFile) {
case 0x02: { /* MSADPCM [Dragon Quest II (iOS) sfx] */
vgmstream->coding_type = coding_MSADPCM;
vgmstream->layout_type = layout_none;
vgmstream->frame_size = read_16bitLE(extradata_offset + 0x02,streamFile);
vgmstream->frame_size = read_16bitLE(extradata_offset + 0x02,sf);
/* adjusted samples; bigger or smaller than base samples, akb lib uses these fields instead
* (base samples may have more than possible and read over file size otherwise, very strange)
* loop_end seems to exist even with loop disabled */
vgmstream->num_samples = read_32bitLE(extradata_offset + 0x04, streamFile);
vgmstream->loop_start_sample = read_32bitLE(extradata_offset + 0x08, streamFile);
vgmstream->loop_end_sample = read_32bitLE(extradata_offset + 0x0c, streamFile);
vgmstream->num_samples = read_32bitLE(extradata_offset + 0x04, sf);
vgmstream->loop_start_sample = read_32bitLE(extradata_offset + 0x08, sf);
vgmstream->loop_end_sample = read_32bitLE(extradata_offset + 0x0c, sf);
break;
}
@ -112,7 +112,7 @@ VGMSTREAM * init_vgmstream_akb(STREAMFILE *streamFile) {
/* extradata + 0x04: Ogg loop start offset */
/* oggs have loop info in the comments */
ogg_vgmstream = init_vgmstream_ogg_vorbis_callbacks(streamFile, NULL, start_offset, &ovmi);
ogg_vgmstream = init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi);
if (ogg_vgmstream) {
close_vgmstream(vgmstream);
return ogg_vgmstream;
@ -128,7 +128,7 @@ VGMSTREAM * init_vgmstream_akb(STREAMFILE *streamFile) {
/* Alt decoding without libvorbis (minor number of beginning samples difference).
* Otherwise same output with (inaudible) +-1 lower byte differences due to rounding. */
case 0x05: { /* Ogg Vorbis [Final Fantasy VI (iOS), Dragon Quest II-VI (iOS)] */
vgmstream->codec_data = init_ffmpeg_offset(streamFile, start_offset,stream_size);
vgmstream->codec_data = init_ffmpeg_offset(sf, start_offset,stream_size);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
@ -145,7 +145,7 @@ VGMSTREAM * init_vgmstream_akb(STREAMFILE *streamFile) {
#ifdef VGM_USE_FFMPEG
case 0x06: { /* M4A with AAC [The World Ends with You (iPad)] */
/* init_vgmstream_akb_mp4 above has priority, but this works fine too */
vgmstream->codec_data = init_ffmpeg_offset(streamFile, start_offset,stream_size-start_offset);
vgmstream->codec_data = init_ffmpeg_offset(sf, start_offset,stream_size-start_offset);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
@ -168,7 +168,7 @@ VGMSTREAM * init_vgmstream_akb(STREAMFILE *streamFile) {
}
/* open the file for reading */
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
if ( !vgmstream_open_stream(vgmstream, sf, start_offset) )
goto fail;
return vgmstream;
@ -180,22 +180,22 @@ fail:
/* AKB2 - found in later SQEX iOS games */
VGMSTREAM * init_vgmstream_akb2(STREAMFILE *streamFile) {
VGMSTREAM * init_vgmstream_akb2(STREAMFILE *sf) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset, material_offset, extradata_offset;
size_t material_size, extradata_size, stream_size;
int loop_flag = 0, channel_count, encryption_flag, codec, sample_rate, num_samples, loop_start, loop_end;
int total_subsongs, target_subsong = streamFile->stream_index;
int total_subsongs, target_subsong = sf->stream_index;
/* check extensions */
/* .akb.bytes is the usual extension in later games */
if ( !check_extensions(streamFile, "akb,bytes") )
if ( !check_extensions(sf, "akb,bytes") )
goto fail;
/* checks */
if (read_32bitBE(0x00,streamFile) != 0x414B4232) /* "AKB2" */
if (read_32bitBE(0x00,sf) != 0x414B4232) /* "AKB2" */
goto fail;
if (read_32bitLE(0x08,streamFile) != get_streamfile_size(streamFile))
if (read_32bitLE(0x08,sf) != get_streamfile_size(sf))
goto fail;
/* 0x04: version */
@ -203,37 +203,37 @@ VGMSTREAM * init_vgmstream_akb2(STREAMFILE *streamFile) {
{
off_t table_offset;
size_t table_size, entry_size;
off_t akb_header_size = read_16bitLE(0x06, streamFile);
int table_count = read_8bit(0x0c, streamFile);
off_t akb_header_size = read_16bitLE(0x06, sf);
int table_count = read_8bit(0x0c, sf);
/* probably each table has its type somewhere, but only seen last table = sound table */
if (table_count > 2) /* 2 only seen in some Mobius FF sound banks */
goto fail;
entry_size = 0x10; /* technically every entry/table has its own size but to simplify... */
table_offset = read_32bitLE(akb_header_size + (table_count-1)*entry_size + 0x04, streamFile);
table_size = read_16bitLE(table_offset + 0x02, streamFile);
table_offset = read_32bitLE(akb_header_size + (table_count-1)*entry_size + 0x04, sf);
table_size = read_16bitLE(table_offset + 0x02, sf);
total_subsongs = read_8bit(table_offset + 0x0f, streamFile); /* can contain 0 entries too */
total_subsongs = read_8bit(table_offset + 0x0f, sf); /* can contain 0 entries too */
if (target_subsong == 0) target_subsong = 1;
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
material_offset = table_offset + read_32bitLE(table_offset + table_size + (target_subsong-1)*entry_size + 0x04, streamFile);
material_offset = table_offset + read_32bitLE(table_offset + table_size + (target_subsong-1)*entry_size + 0x04, sf);
}
/** stream header (material) **/
/* 0x00: 0? */
codec = read_8bit(material_offset+0x01,streamFile);
channel_count = read_8bit(material_offset+0x02,streamFile);
encryption_flag = read_8bit(material_offset+0x03,streamFile);
material_size = read_16bitLE(material_offset+0x04,streamFile);
sample_rate = (uint16_t)read_16bitLE(material_offset+0x06,streamFile);
stream_size = read_32bitLE(material_offset+0x08,streamFile);
num_samples = read_32bitLE(material_offset+0x0c,streamFile);
codec = read_8bit(material_offset+0x01,sf);
channel_count = read_8bit(material_offset+0x02,sf);
encryption_flag = read_8bit(material_offset+0x03,sf);
material_size = read_16bitLE(material_offset+0x04,sf);
sample_rate = (uint16_t)read_16bitLE(material_offset+0x06,sf);
stream_size = read_32bitLE(material_offset+0x08,sf);
num_samples = read_32bitLE(material_offset+0x0c,sf);
loop_start = read_32bitLE(material_offset+0x10,streamFile);
loop_end = read_32bitLE(material_offset+0x14,streamFile);
extradata_size = read_32bitLE(material_offset+0x18,streamFile);
loop_start = read_32bitLE(material_offset+0x10,sf);
loop_end = read_32bitLE(material_offset+0x14,sf);
extradata_size = read_32bitLE(material_offset+0x18,sf);
/* rest: ? (empty or 0x3f80) */
loop_flag = (loop_end > loop_start);
@ -269,14 +269,14 @@ VGMSTREAM * init_vgmstream_akb2(STREAMFILE *streamFile) {
case 0x02: { /* MSADPCM [The Irregular at Magic High School Lost Zero (Android)] */
vgmstream->coding_type = coding_MSADPCM;
vgmstream->layout_type = layout_none;
vgmstream->frame_size = read_16bitLE(extradata_offset + 0x02, streamFile);
vgmstream->frame_size = read_16bitLE(extradata_offset + 0x02, sf);
/* adjusted samples; bigger or smaller than base samples, akb lib uses these fields instead
* (base samples may have more than possible and read over file size otherwise, very strange)
* loop_end seems to exist even with loop disabled */
vgmstream->num_samples = read_32bitLE(extradata_offset + 0x04, streamFile);
vgmstream->loop_start_sample = read_32bitLE(extradata_offset + 0x08, streamFile);
vgmstream->loop_end_sample = read_32bitLE(extradata_offset + 0x0c, streamFile);
vgmstream->num_samples = read_32bitLE(extradata_offset + 0x04, sf);
vgmstream->loop_start_sample = read_32bitLE(extradata_offset + 0x08, sf);
vgmstream->loop_end_sample = read_32bitLE(extradata_offset + 0x0c, sf);
break;
}
@ -289,7 +289,7 @@ VGMSTREAM * init_vgmstream_akb2(STREAMFILE *streamFile) {
ovmi.total_subsongs = total_subsongs;
ovmi.stream_size = stream_size;
ogg_vgmstream = init_vgmstream_ogg_vorbis_callbacks(streamFile, NULL, start_offset, &ovmi);
ogg_vgmstream = init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi);
if (ogg_vgmstream) {
ogg_vgmstream->num_streams = vgmstream->num_streams;
ogg_vgmstream->stream_size = vgmstream->stream_size;
@ -310,7 +310,7 @@ VGMSTREAM * init_vgmstream_akb2(STREAMFILE *streamFile) {
case 0x05: { /* Ogg Vorbis [The World Ends with You (iOS / latest update)] */
ffmpeg_codec_data *ffmpeg_data;
ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset,stream_size);
ffmpeg_data = init_ffmpeg_offset(sf, start_offset,stream_size);
if ( !ffmpeg_data ) goto fail;
vgmstream->codec_data = ffmpeg_data;
@ -319,8 +319,8 @@ VGMSTREAM * init_vgmstream_akb2(STREAMFILE *streamFile) {
/* When loop_flag num_samples may be much larger than real num_samples (it's fine when looping is off)
* Actual num_samples would be loop_end_sample+1, but more testing is needed */
vgmstream->num_samples = read_32bitLE(material_offset+0x0c,streamFile);//num_samples;
vgmstream->loop_start_sample = read_32bitLE(material_offset+0x10,streamFile);//loop_start;
vgmstream->num_samples = read_32bitLE(material_offset+0x0c,sf);//num_samples;
vgmstream->loop_start_sample = read_32bitLE(material_offset+0x10,sf);//loop_start;
vgmstream->loop_end_sample = loop_end;
break;
}
@ -331,7 +331,7 @@ VGMSTREAM * init_vgmstream_akb2(STREAMFILE *streamFile) {
}
/* open the file for reading */
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
if ( !vgmstream_open_stream(vgmstream, sf, start_offset) )
goto fail;
return vgmstream;

View File

@ -27,7 +27,7 @@ VGMSTREAM* init_vgmstream_ao(STREAMFILE *sf) {
/* AlphaOgg defines up to 16 loop points for some reason */
start_offset = 0xc8;
vgmstream = init_vgmstream_ogg_vorbis_callbacks(sf, NULL, start_offset, &ovmi);
vgmstream = init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi);
}
#else
goto fail;

View File

@ -1,82 +1,82 @@
#ifndef _BAR_STREAMFILE_H_
#define _BAR_STREAMFILE_H_
#include "../streamfile.h"
/* a streamfile wrapping another for decryption */
enum {BAR_KEY_LENGTH = 16};
// don't know if this is unique, but seems accurate
static const uint8_t bar_key[BAR_KEY_LENGTH] = {
0xbd,0x14,0x0e,0x0a,0x91,0xeb,0xaa,0xf6,
0x11,0x44,0x17,0xc2,0x1c,0xe4,0x66,0x80
};
typedef struct _BARSTREAMFILE {
STREAMFILE sf;
STREAMFILE *real_file;
} BARSTREAMFILE;
/*static*/ STREAMFILE *wrap_bar_STREAMFILE(STREAMFILE *file);
static size_t read_bar(BARSTREAMFILE *streamFile, uint8_t *dest, off_t offset, size_t length) {
off_t i;
size_t read_length = streamFile->real_file->read(streamFile->real_file, dest, offset, length);
for (i = 0; i < read_length; i++) {
dest[i] = dest[i] ^ bar_key[(i+offset)%BAR_KEY_LENGTH];
}
return read_length;
}
static size_t get_size_bar(BARSTREAMFILE *streamFile) {
return streamFile->real_file->get_size(streamFile->real_file);
}
static size_t get_offset_bar(BARSTREAMFILE *streamFile) {
return streamFile->real_file->get_offset(streamFile->real_file);
}
static void get_name_bar(BARSTREAMFILE *streamFile, char *name, size_t length) {
streamFile->real_file->get_name(streamFile->real_file, name, length);
}
STREAMFILE *open_bar(BARSTREAMFILE *streamFile, const char * const filename, size_t buffersize) {
STREAMFILE *newfile = streamFile->real_file->open(streamFile->real_file,filename,buffersize);
if (!newfile)
return NULL;
return wrap_bar_STREAMFILE(newfile);
}
static void close_bar(BARSTREAMFILE *streamFile) {
streamFile->real_file->close(streamFile->real_file);
free(streamFile);
return;
}
/*static*/ STREAMFILE *wrap_bar_STREAMFILE(STREAMFILE *file) {
BARSTREAMFILE *streamfile = malloc(sizeof(BARSTREAMFILE));
if (!streamfile)
return NULL;
memset(streamfile, 0, sizeof(BARSTREAMFILE));
streamfile->sf.read = (void*)read_bar;
streamfile->sf.get_size = (void*)get_size_bar;
streamfile->sf.get_offset = (void*)get_offset_bar;
streamfile->sf.get_name = (void*)get_name_bar;
streamfile->sf.open = (void*)open_bar;
streamfile->sf.close = (void*)close_bar;
streamfile->real_file = file;
return &streamfile->sf;
}
#endif /* _BAR_STREAMFILE_H_ */
#ifndef _BAR_STREAMFILE_H_
#define _BAR_STREAMFILE_H_
#include "../streamfile.h"
/* a streamfile wrapping another for decryption */
enum {BAR_KEY_LENGTH = 16};
// don't know if this is unique, but seems accurate
static const uint8_t bar_key[BAR_KEY_LENGTH] = {
0xbd,0x14,0x0e,0x0a,0x91,0xeb,0xaa,0xf6,
0x11,0x44,0x17,0xc2,0x1c,0xe4,0x66,0x80
};
typedef struct _BARSTREAMFILE {
STREAMFILE sf;
STREAMFILE *real_file;
} BARSTREAMFILE;
/*static*/ STREAMFILE *wrap_bar_STREAMFILE(STREAMFILE *file);
static size_t read_bar(BARSTREAMFILE *streamFile, uint8_t *dest, off_t offset, size_t length) {
off_t i;
size_t read_length = streamFile->real_file->read(streamFile->real_file, dest, offset, length);
for (i = 0; i < read_length; i++) {
dest[i] = dest[i] ^ bar_key[(i+offset)%BAR_KEY_LENGTH];
}
return read_length;
}
static size_t get_size_bar(BARSTREAMFILE *streamFile) {
return streamFile->real_file->get_size(streamFile->real_file);
}
static size_t get_offset_bar(BARSTREAMFILE *streamFile) {
return streamFile->real_file->get_offset(streamFile->real_file);
}
static void get_name_bar(BARSTREAMFILE *streamFile, char *name, size_t length) {
streamFile->real_file->get_name(streamFile->real_file, name, length);
}
static STREAMFILE *open_bar(BARSTREAMFILE *streamFile, const char * const filename, size_t buffersize) {
STREAMFILE *newfile = streamFile->real_file->open(streamFile->real_file,filename,buffersize);
if (!newfile)
return NULL;
return wrap_bar_STREAMFILE(newfile);
}
static void close_bar(BARSTREAMFILE *streamFile) {
streamFile->real_file->close(streamFile->real_file);
free(streamFile);
return;
}
/*static*/ STREAMFILE *wrap_bar_STREAMFILE(STREAMFILE *file) {
BARSTREAMFILE *streamfile = malloc(sizeof(BARSTREAMFILE));
if (!streamfile)
return NULL;
memset(streamfile, 0, sizeof(BARSTREAMFILE));
streamfile->sf.read = (void*)read_bar;
streamfile->sf.get_size = (void*)get_size_bar;
streamfile->sf.get_offset = (void*)get_offset_bar;
streamfile->sf.get_name = (void*)get_name_bar;
streamfile->sf.open = (void*)open_bar;
streamfile->sf.close = (void*)close_bar;
streamfile->real_file = file;
return &streamfile->sf;
}
#endif /* _BAR_STREAMFILE_H_ */

View File

@ -2,11 +2,11 @@
#include "../layout/layout.h"
#define TXT_LINE_MAX 0x1000
static int get_falcom_looping(STREAMFILE *streamFile, int *out_loop_start, int *out_loop_end);
static int get_falcom_looping(STREAMFILE* sf, int* p_loop_start, int* p_loop_end);
/* .DEC/DE2 - from Falcom PC games (Xanadu Next, Zwei!!, VM Japan, Gurumin) */
VGMSTREAM * init_vgmstream_dec(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
VGMSTREAM* init_vgmstream_dec(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
off_t riff_off = 0x00;
size_t pcm_size = 0;
@ -16,42 +16,42 @@ VGMSTREAM * init_vgmstream_dec(STREAMFILE *streamFile) {
/* checks
* .dec: main,
* .de2: Gurumin (PC) */
if ( !check_extensions(streamFile,"dec,de2") )
if (!check_extensions(sf,"dec,de2"))
goto fail;
/* Gurumin has extra data, maybe related to rhythm (~0x50000) */
if (check_extensions(streamFile,"de2")) {
if (check_extensions(sf,"de2")) {
/* still not sure what this is for, but consistently 0xb */
if (read_32bitLE(0x04,streamFile) != 0x0b) goto fail;
if (read_32bitLE(0x04,sf) != 0x0b) goto fail;
/* legitimate! really! */
riff_off = 0x10 + (read_32bitLE(0x0c,streamFile) ^ read_32bitLE(0x04,streamFile));
riff_off = 0x10 + (read_32bitLE(0x0c,sf) ^ read_32bitLE(0x04,sf));
}
/* fake PCM RIFF header (the original WAV's) wrapping MS-ADPCM */
if (read_32bitBE(riff_off+0x00,streamFile) != 0x52494646 || /* "RIFF" */
read_32bitBE(riff_off+0x08,streamFile) != 0x57415645) /* "WAVE" */
if (!is_id32be(riff_off+0x00,sf, "RIFF") ||
!is_id32be(riff_off+0x08,sf, "WAVE"))
goto fail;
if (read_32bitBE(riff_off+0x0c,streamFile) == 0x50414420) { /* "PAD " (Zwei!!), blank with wrong chunk size */
if (is_id32be(riff_off+0x0c,sf, "PAD ")) { /* blank with wrong chunk size [Zwei!! ())PC)]*/
sample_rate = 44100;
channel_count = 2;
pcm_size = read_32bitLE(riff_off+0x04,streamFile) - 0x24;
pcm_size = read_32bitLE(riff_off+0x04,sf) - 0x24;
/* somehow there is garbage at the beginning of some tracks */
}
else if (read_32bitBE(riff_off+0x0c,streamFile) == 0x666D7420) { /* "fmt " (rest) */
//if (read_32bitLE(riff_off+0x10,streamFile) != 0x12) goto fail; /* 0x10 in some */
if (read_16bitLE(riff_off+0x14,streamFile) != 0x01) goto fail; /* PCM (actually MS-ADPCM) */
if (read_16bitLE(riff_off+0x20,streamFile) != 4 ||
read_16bitLE(riff_off+0x22,streamFile) != 16) goto fail; /* 16-bit */
else if (is_id32be(riff_off+0x0c,sf, "fmt ")) {
//if (read_32bitLE(riff_off+0x10,sf) != 0x12) goto fail; /* 0x10 in some */
if (read_16bitLE(riff_off+0x14,sf) != 0x01) goto fail; /* PCM (actually MS-ADPCM) */
if (read_16bitLE(riff_off+0x20,sf) != 4 ||
read_16bitLE(riff_off+0x22,sf) != 16) goto fail; /* 16-bit */
channel_count = read_16bitLE(riff_off+0x16,streamFile);
sample_rate = read_32bitLE(riff_off+0x18,streamFile);
if (read_32bitBE(riff_off+0x24,streamFile) == 0x64617461) { /* "data" size except in some Zwei!! */
pcm_size = read_32bitLE(riff_off+0x28,streamFile);
channel_count = read_16bitLE(riff_off+0x16,sf);
sample_rate = read_32bitLE(riff_off+0x18,sf);
if (read_32bitBE(riff_off+0x24,sf) == 0x64617461) { /* "data" size except in some Zwei!! */
pcm_size = read_32bitLE(riff_off+0x28,sf);
} else {
pcm_size = read_32bitLE(riff_off+0x04,streamFile) - 0x24;
pcm_size = read_32bitLE(riff_off+0x04,sf) - 0x24;
}
}
else {
@ -62,7 +62,7 @@ VGMSTREAM * init_vgmstream_dec(STREAMFILE *streamFile) {
goto fail;
start_offset = riff_off + 0x2c;
loop_flag = get_falcom_looping(streamFile, &loop_start, &loop_end);
loop_flag = get_falcom_looping(sf, &loop_start, &loop_end);
/* build the VGMSTREAM */
@ -79,7 +79,7 @@ VGMSTREAM * init_vgmstream_dec(STREAMFILE *streamFile) {
vgmstream->frame_size = 0x800;
vgmstream->layout_type = layout_blocked_dec;
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
@ -91,7 +91,7 @@ fail:
/* Falcom loves loop points in external text files, here we parse them */
typedef enum { XANADU_NEXT, ZWEI, DINOSAUR_RESURRECTION, GURUMIN } falcom_loop_t;
static int get_falcom_looping(STREAMFILE *streamFile, int *out_loop_start, int *out_loop_end) {
static int get_falcom_looping(STREAMFILE *sf, int *out_loop_start, int *out_loop_end) {
STREAMFILE *streamText;
off_t txt_offset = 0x00;
falcom_loop_t type;
@ -100,23 +100,23 @@ static int get_falcom_looping(STREAMFILE *streamFile, int *out_loop_start, int *
/* try one of the many loop files */
if ((streamText = open_streamfile_by_filename(streamFile,"bgm.tbl")) != NULL) {
if ((streamText = open_streamfile_by_filename(sf,"bgm.tbl")) != NULL) {
type = XANADU_NEXT;
}
else if ((streamText = open_streamfile_by_filename(streamFile,"bgm.scr")) != NULL) {
else if ((streamText = open_streamfile_by_filename(sf,"bgm.scr")) != NULL) {
type = ZWEI;
}
else if ((streamText = open_streamfile_by_filename(streamFile,"loop.txt")) != NULL) { /* actual name in Shift JIS, 0x838B815B8376 */
else if ((streamText = open_streamfile_by_filename(sf,"loop.txt")) != NULL) { /* actual name in Shift JIS, 0x838B815B8376 */
type = DINOSAUR_RESURRECTION;
}
else if ((streamText = open_streamfile_by_filename(streamFile,"map.itm")) != NULL) {
else if ((streamText = open_streamfile_by_filename(sf,"map.itm")) != NULL) {
type = GURUMIN;
}
else {
goto end;
}
get_streamfile_filename(streamFile,filename,TXT_LINE_MAX);
get_streamfile_filename(sf,filename,TXT_LINE_MAX);
/* read line by line */
while (txt_offset < get_streamfile_size(streamText)) {
@ -166,6 +166,9 @@ static int get_falcom_looping(STREAMFILE *streamFile, int *out_loop_start, int *
goto end;
}
break;
default:
break;
}
}

View File

@ -508,7 +508,7 @@ fail:
}
/* open map/mpf+mus pairs that aren't exact pairs, since EA's games can load any combo */
static STREAMFILE *open_mapfile_pair(STREAMFILE* sf, int track, int num_tracks) {
static STREAMFILE *open_mapfile_pair(STREAMFILE* sf, int track /*, int num_tracks*/) {
static const char *const mapfile_pairs[][2] = {
/* standard cases, replace map part with mus part (from the end to preserve prefixes) */
{"game.mpf", "Game_Stream.mus"}, /* Skate 1/2/3 */
@ -685,7 +685,7 @@ VGMSTREAM* init_vgmstream_ea_mpf_mus_eaac(STREAMFILE* sf) {
}
/* open MUS file that matches this track */
musFile = open_mapfile_pair(sf, i, num_tracks);
musFile = open_mapfile_pair(sf, i);//, num_tracks
if (!musFile)
goto fail;
@ -1136,6 +1136,8 @@ static VGMSTREAM* init_vgmstream_eaaudiocore_header(STREAMFILE* sf_head, STREAMF
eaac.loop_offset = read_32bitBE(header_offset + 0x10, sf_head);
}
break;
default:
goto fail;
}
/* get data offsets */
@ -1151,6 +1153,8 @@ static VGMSTREAM* init_vgmstream_eaaudiocore_header(STREAMFILE* sf_head, STREAMF
eaac.prefetch_offset = header_offset + header_size;
eaac.stream_offset = start_offset;
break;
default:
goto fail;
}
} else {
eaac.stream_offset = header_offset - 0x04 + header_block_size;
@ -1340,7 +1344,7 @@ static VGMSTREAM* init_vgmstream_eaaudiocore_header(STREAMFILE* sf_head, STREAMF
#ifdef VGM_USE_MPEG
case EAAC_CODEC_EAMP3: { /* "EM30": EA-MP3 [Need for Speed 2015 (PS4)] */
case EAAC_CODEC_EAMP3: { /* "EM30": EA-MP3 [Need for Speed 2015 (PS4), FIFA 2021 (PC)] */
mpeg_custom_config cfg = {0};
temp_sf = setup_eaac_audio_streamfile(sf, eaac.version, eaac.codec, eaac.streamed,0,0, 0x00);
@ -1551,6 +1555,8 @@ static STREAMFILE *setup_eaac_streamfile(eaac_header *ea, STREAMFILE* sf_head, S
sf_segments[0] = NULL;
sf_segments[1] = NULL;
break;
default:
goto fail;
}
} else {
data_size = calculate_eaac_size(sf_head, ea, ea->num_samples, ea->stream_offset, 0);
@ -1603,29 +1609,29 @@ static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *sf
switch(eaac->codec) {
#ifdef VGM_USE_FFMPEG
case EAAC_CODEC_EAXMA: {
eaac_header temp_eaac = *eaac; /* equivalent to memcpy... I think */
temp_eaac.loop_flag = 0;
temp_eaac.num_samples = num_samples[i];
case EAAC_CODEC_EAXMA: {
eaac_header temp_eaac = *eaac; /* equivalent to memcpy... I think */
temp_eaac.loop_flag = 0;
temp_eaac.num_samples = num_samples[i];
start_offset = 0x00; /* must point to the custom streamfile's beginning */
start_offset = 0x00; /* must point to the custom streamfile's beginning */
/* layers inside segments, how trippy */
data->segments[i]->layout_data = build_layered_eaaudiocore(sf_data, &temp_eaac, offsets[i]);
if (!data->segments[i]->layout_data) goto fail;
data->segments[i]->coding_type = coding_FFmpeg;
data->segments[i]->layout_type = layout_layered;
break;
}
/* layers inside segments, how trippy */
data->segments[i]->layout_data = build_layered_eaaudiocore(sf_data, &temp_eaac, offsets[i]);
if (!data->segments[i]->layout_data) goto fail;
data->segments[i]->coding_type = coding_FFmpeg;
data->segments[i]->layout_type = layout_layered;
break;
}
#endif
case EAAC_CODEC_XAS1: {
start_offset = offsets[i];
case EAAC_CODEC_XAS1: {
start_offset = offsets[i];
data->segments[i]->coding_type = coding_EA_XAS_V1;
data->segments[i]->layout_type = layout_blocked_ea_sns;
break;
}
data->segments[i]->coding_type = coding_EA_XAS_V1;
data->segments[i]->layout_type = layout_blocked_ea_sns;
break;
}
#ifdef VGM_USE_MPEG
case EAAC_CODEC_EALAYER3_V1:
@ -1689,8 +1695,8 @@ static layered_layout_data* build_layered_eaaudiocore(STREAMFILE *sf_data, eaac_
data->layers[i]->loop_start_sample = eaac->loop_start;
data->layers[i]->loop_end_sample = eaac->loop_end;
#ifdef VGM_USE_FFMPEG
switch(eaac->codec) {
#ifdef VGM_USE_FFMPEG
/* EA-XMA uses completely separate 1/2ch streams, unlike standard XMA that interleaves 1/2ch
* streams with a skip counter to reinterleave (so EA-XMA streams don't have skips set) */
case EAAC_CODEC_EAXMA: {
@ -1743,11 +1749,10 @@ static layered_layout_data* build_layered_eaaudiocore(STREAMFILE *sf_data, eaac_
data->layers[i]->layout_type = layout_none;
break;
}
}
#else
goto fail;
#endif
default:
goto fail;
}
if (!vgmstream_open_stream(data->layers[i], temp_sf, 0x00)) {
goto fail;

View File

@ -637,7 +637,7 @@ fail:
/* open map/mpf+mus pairs that aren't exact pairs, since EA's games can load any combo */
static STREAMFILE* open_mapfile_pair(STREAMFILE* sf, int track, int num_tracks) {
static STREAMFILE* open_mapfile_pair(STREAMFILE* sf, int track /*, int num_tracks*/) {
static const char *const mapfile_pairs[][2] = {
/* standard cases, replace map part with mus part (from the end to preserve prefixes) */
{"MUS_CTRL.MPF", "MUS_STR.MUS"}, /* GoldenEye - Rogue Agent (PS2) */
@ -760,7 +760,7 @@ VGMSTREAM* init_vgmstream_ea_map_mus(STREAMFILE* sf) {
version = read_8bit(0x04, sf);
if (version > 1) goto fail;
sf_mus = open_mapfile_pair(sf, 0, 1);
sf_mus = open_mapfile_pair(sf, 0); //, 1
if (!sf_mus) goto fail;
/*
@ -994,7 +994,7 @@ VGMSTREAM* init_vgmstream_ea_mpf_mus(STREAMFILE* sf) {
goto fail;
/* open MUS file that matches this track */
sf_mus = open_mapfile_pair(sf, i, num_tracks);
sf_mus = open_mapfile_pair(sf, i); //, num_tracks
if (!sf_mus)
goto fail;

View File

@ -23,7 +23,7 @@ static int find_meta_loops(ffmpeg_codec_data* data, int32_t* p_loop_start, int32
VGMSTREAM* init_vgmstream_ffmpeg(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
ffmpeg_codec_data* data = NULL;
int loop_flag = 0;
int loop_flag = 0, channels, sample_rate;
int32_t loop_start = 0, loop_end = 0, num_samples = 0, encoder_delay = 0;
int total_subsongs, target_subsong = sf->stream_index;
@ -35,9 +35,12 @@ VGMSTREAM* init_vgmstream_ffmpeg(STREAMFILE* sf) {
if (get_streamfile_size(sf) <= 0x1000)
goto fail;
// many PSP rips have poorly demuxed videos with a failty RIFF, allow for now
#if 0
/* reject some formats handled elsewhere (better fail and check there than let buggy FFmpeg take over) */
if (check_extensions(sf, "at3"))
goto fail;
#endif
if (target_subsong == 0) target_subsong = 1;
@ -45,18 +48,18 @@ VGMSTREAM* init_vgmstream_ffmpeg(STREAMFILE* sf) {
data = init_ffmpeg_header_offset_subsong(sf, NULL, 0, 0, get_streamfile_size(sf), target_subsong);
if (!data) return NULL;
total_subsongs = data->streamCount; /* uncommon, ex. wmv [Lost Odyssey (X360)] */
total_subsongs = ffmpeg_get_subsong_count(data); /* uncommon, ex. wmv [Lost Odyssey (X360)] */
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
/* try to get .pos data */
{
uint8_t posbuf[4+4+4];
uint8_t posbuf[0x04*3];
if (read_pos_file(posbuf, 4+4+4, sf)) {
loop_start = get_s32le(posbuf+0);
loop_end = get_s32le(posbuf+4);
if (read_pos_file(posbuf, sizeof(posbuf), sf)) {
loop_start = get_s32le(posbuf+0x00);
loop_end = get_s32le(posbuf+0x04);
loop_flag = 1; /* incorrect looping will be validated outside */
/* FFmpeg can't always determine totalSamples correctly so optionally load it (can be 0/NULL)
/* FFmpeg can't always determine samples correctly so optionally load it (can be 0/NULL)
* won't crash and will output silence if no loop points and bigger than actual stream's samples */
num_samples = get_s32le(posbuf+8);
}
@ -82,6 +85,9 @@ VGMSTREAM* init_vgmstream_ffmpeg(STREAMFILE* sf) {
* .mus: Marc Ecko's Getting Up (PC) */
if (!num_samples && check_extensions(sf, "mp3,lmp3,mus")) {
num_samples = mpeg_get_samples(sf, 0x00, get_streamfile_size(sf));
/* this seems correct thankfully */
//ffmpeg_set_skip_samples(data, encoder_delay);
}
#endif
@ -100,18 +106,22 @@ VGMSTREAM* init_vgmstream_ffmpeg(STREAMFILE* sf) {
/* default but often inaccurate when calculated using bitrate (wrong for VBR) */
if (!num_samples) {
num_samples = data->totalSamples; /* may be 0 if FFmpeg can't precalculate it */
num_samples = ffmpeg_get_samples(data); /* may be 0 if FFmpeg can't precalculate it */
}
channels = ffmpeg_get_channels(data);
sample_rate = ffmpeg_get_sample_rate(data);
/* build VGMSTREAM */
vgmstream = allocate_vgmstream(data->channels, loop_flag);
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = data->sampleRate;
vgmstream->meta_type = meta_FFMPEG;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->sample_rate = sample_rate;
vgmstream->codec_data = data;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
vgmstream->num_samples = num_samples;
@ -211,7 +221,7 @@ static int find_meta_loops(ffmpeg_codec_data* data, int32_t* p_loop_start, int32
if (loop_end <= 0) {
// Looks a calculation was not possible, or tag value is wrongly set. Use the end of track as end value
loop_end = data->totalSamples;
loop_end = ffmpeg_get_samples(data);
}
if (loop_start <= 0) {

View File

@ -1,5 +1,5 @@
#ifndef _FSB_ENCRYPTED_STREAMFILE_H_
#define _FSB_ENCRYPTED_H_
#define _FSB_ENCRYPTED_STREAMFILE_H_
#define FSB_KEY_MAX 0x10000 //0x168
@ -71,4 +71,4 @@ static STREAMFILE* setup_fsb_streamfile(STREAMFILE* sf, const uint8_t* key, size
return new_sf;
}
#endif /* _FSB5_STREAMFILE_H_ */
#endif /* _FSB_ENCRYPTED_STREAMFILE_H_ */

View File

@ -307,7 +307,7 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) {
if ( !ffmpeg_data ) goto fail;
//if (vgmstream->num_samples == 0)
// vgmstream->num_samples = ffmpeg_data->totalSamples; /* sometimes works */
// vgmstream->num_samples = ffmpeg_get_samples(ffmpeg_data); /* sometimes works */
}
else {
/* fake header FFmpeg */

View File

@ -2,16 +2,17 @@
#include "../coding/coding.h"
/* .gin - EA engine sounds [Need for Speed: Most Wanted (multi)] */
VGMSTREAM * init_vgmstream_gin(STREAMFILE *streamFile) {
VGMSTREAM * init_vgmstream_gin(STREAMFILE *sf) {
VGMSTREAM *vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count, sample_rate, num_samples;
if (!check_extensions(streamFile, "gin"))
if (!check_extensions(sf, "gin"))
goto fail;
/* checks */
if (read_32bitBE(0x00, streamFile) != 0x476E7375) /* "Gnsu" */
if (!is_id32be(0x00, sf, "Gnsu") && /* original */
!is_id32be(0x00, sf, "Octn")) /* later (2013+) games, looks same as "Gnsu" */
goto fail;
/* contains mapped values for engine RPM sounds but we'll just play the whole thing */
@ -21,11 +22,11 @@ VGMSTREAM * init_vgmstream_gin(STREAMFILE *streamFile) {
/* 0x14: RPM ??? table size */
/* always LE even on X360/PS3 */
num_samples = read_32bitLE(0x18, streamFile);
sample_rate = read_32bitLE(0x1c, streamFile);
num_samples = read_u32le(0x18, sf);
sample_rate = read_u32le(0x1c, sf);
start_offset = 0x20 +
(read_32bitLE(0x10, streamFile) + 1) * 0x04 +
(read_32bitLE(0x14, streamFile) + 1) * 0x04;
(read_u32le(0x10, sf) + 1) * 0x04 +
(read_u32le(0x14, sf) + 1) * 0x04;
channel_count = 1;
loop_flag = 0;
@ -44,7 +45,7 @@ VGMSTREAM * init_vgmstream_gin(STREAMFILE *streamFile) {
/* calculate size for TMX */
vgmstream->stream_size = (align_size_to_block(num_samples, 32) / 32) * 0x13;
if (!vgmstream_open_stream(vgmstream, streamFile, start_offset))
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;

View File

@ -1,6 +1,7 @@
#include "meta.h"
#include "hca_keys.h"
#include "../coding/coding.h"
#include "clHCA.h"
//#define HCA_BRUTEFORCE
#ifdef HCA_BRUTEFORCE
@ -15,7 +16,7 @@ VGMSTREAM* init_vgmstream_hca(STREAMFILE* sf) {
}
VGMSTREAM* init_vgmstream_hca_subkey(STREAMFILE* sf, uint16_t subkey) {
VGMSTREAM * vgmstream = NULL;
VGMSTREAM* vgmstream = NULL;
hca_codec_data* hca_data = NULL;
clHCA_stInfo* hca_info;
@ -152,26 +153,32 @@ static inline void test_key(hca_codec_data* hca_data, uint64_t key, uint16_t sub
static void find_hca_key(hca_codec_data* hca_data, uint64_t* p_keycode, uint16_t subkey) {
const size_t keys_length = sizeof(hcakey_list) / sizeof(hcakey_info);
int best_score = -1;
int i,j;
int i;
*p_keycode = 0xCC55463930DBE1AB; /* defaults to PSO2 key, most common */
for (i = 0; i < keys_length; i++) {
uint64_t key = hcakey_list[i].key;
size_t subkeys_size = hcakey_list[i].subkeys_size;
const uint16_t *subkeys = hcakey_list[i].subkeys;
test_key(hca_data, key, subkey, &best_score, p_keycode);
if (best_score == 1)
goto done;
if (subkeys_size > 0 && subkey == 0) {
for (j = 0; j < subkeys_size; j++) {
test_key(hca_data, key, subkeys[j], &best_score, p_keycode);
if (best_score == 1)
goto done;
#if 0
{
int j;
size_t subkeys_size = hcakey_list[i].subkeys_size;
const uint16_t *subkeys = hcakey_list[i].subkeys;
if (subkeys_size > 0 && subkey == 0) {
for (j = 0; j < subkeys_size; j++) {
test_key(hca_data, key, subkeys[j], &best_score, p_keycode);
if (best_score == 1)
goto done;
}
}
}
#endif
}
done:

View File

@ -5,8 +5,10 @@
typedef struct {
uint64_t key; /* hca key or seed ('user') key */
const uint16_t *subkeys; /* scramble subkey table for seed key */
#if 0
const uint16_t* subkeys; /* scramble subkey table for seed key */
size_t subkeys_size; /* size of the derivation subkey table */
#endif
} hcakey_info;
@ -410,6 +412,9 @@ static const hcakey_info hcakey_list[] = {
/* Dragon Quest Tact (Android) */
{3234477171400153310}, // 2CE32BD9B36A98DE
/* Alchemy Stars (Android) */
{1564789515523}, // 0000016C54B92503
/* D4DJ Groovy Mix (Android) [base files] */
{393410674916959300}, // 0575ACECA945A444
/* D4DJ Groovy Mix (Android) [music_* files, per-song later mixed with subkey] */
@ -711,6 +716,9 @@ static const hcakey_info hcakey_list[] = {
{0x78bec41dd27d8788}, //music_5050074
{0x52c250eade92393b}, //music_9010001
{0xfea0d6adff136868}, //music_9050001
// Mini 4WD Hyper Dash Grand Prix (Android)
{7957824642808300098}, // 6E6FDF59AB704242
};
#endif/*_HCA_KEYS_H_*/

View File

@ -3,49 +3,49 @@
/* HIS - Her Interactive games [Nancy Drew series (PC)] */
VGMSTREAM * init_vgmstream_his(STREAMFILE *streamFile) {
VGMSTREAM * init_vgmstream_his(STREAMFILE *sf) {
VGMSTREAM * vgmstream = NULL;
int channel_count, loop_flag = 0, bps, sample_rate, num_samples, version;
off_t start_offset;
/* checks */
if (!check_extensions(streamFile, "his"))
if (!check_extensions(sf, "his"))
goto fail;
if (read_32bitBE(0x00,streamFile) == 0x48657220) { /* "Her Interactive Sound\x1a" */
if (read_32bitBE(0x00,sf) == 0x48657220) { /* "Her Interactive Sound\x1a" */
/* Nancy Drew: Secrets Can Kill (PC) */
version = 0;
channel_count = read_16bitLE(0x16,streamFile);
sample_rate = read_32bitLE(0x18,streamFile);
channel_count = read_16bitLE(0x16,sf);
sample_rate = read_32bitLE(0x18,sf);
/* 0x1c: bitrate */
/* 0x20: block size */
bps = read_16bitLE(0x22,streamFile);
bps = read_16bitLE(0x22,sf);
if (read_32bitBE(0x24,streamFile) != 0x64617461) /* "data" */
if (read_32bitBE(0x24,sf) != 0x64617461) /* "data" */
goto fail;
num_samples = pcm_bytes_to_samples(read_32bitLE(0x28,streamFile), channel_count, bps);
num_samples = pcm_bytes_to_samples(read_32bitLE(0x28,sf), channel_count, bps);
start_offset = 0x2c;
}
else if (read_32bitBE(0x00,streamFile) == 0x48495300) { /* HIS\0 */
else if (read_32bitBE(0x00,sf) == 0x48495300) { /* HIS\0 */
/* most(?) others */
version = read_32bitLE(0x04,streamFile);
version = read_32bitLE(0x04,sf);
/* 0x08: codec */
channel_count = read_16bitLE(0x0a,streamFile);
sample_rate = read_32bitLE(0x0c,streamFile);
channel_count = read_16bitLE(0x0a,sf);
sample_rate = read_32bitLE(0x0c,sf);
/* 0x10: bitrate */
/* 0x14: block size */
bps = read_16bitLE(0x16,streamFile);
bps = read_16bitLE(0x16,sf);
num_samples = pcm_bytes_to_samples(read_32bitLE(0x18,streamFile), channel_count, bps); /* true even for Ogg */
num_samples = pcm_bytes_to_samples(read_32bitLE(0x18,sf), channel_count, bps); /* true even for Ogg */
/* later games use "OggS" */
if (version == 1)
start_offset = 0x1c; /* Nancy Drew: The Final Scene (PC) */
else if (version == 2 && read_32bitBE(0x1e,streamFile) == 0x4F676753)
else if (version == 2 && read_32bitBE(0x1e,sf) == 0x4F676753)
start_offset = 0x1e; /* Nancy Drew: The Haunted Carousel (PC) */
else if (version == 2 && read_32bitBE(0x20,streamFile) == 0x4F676753)
else if (version == 2 && read_32bitBE(0x20,sf) == 0x4F676753)
start_offset = 0x20; /* Nancy Drew: The Silent Spy (PC) */
else
goto fail;
@ -60,7 +60,7 @@ VGMSTREAM * init_vgmstream_his(STREAMFILE *streamFile) {
ogg_vorbis_meta_info_t ovmi = {0};
ovmi.meta_type = meta_HIS;
return init_vgmstream_ogg_vorbis_callbacks(streamFile, NULL, start_offset, &ovmi);
return init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi);
#else
goto fail;
#endif
@ -89,7 +89,7 @@ VGMSTREAM * init_vgmstream_his(STREAMFILE *streamFile) {
goto fail;
}
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
if (!vgmstream_open_stream(vgmstream,sf,start_offset))
goto fail;
return vgmstream;

View File

@ -80,7 +80,7 @@ VGMSTREAM* init_vgmstream_ikm_pc(STREAMFILE* sf) {
ovmi.loop_flag = ovmi.loop_end > 0;
ovmi.stream_size = read_s32le(0x24, sf);
vgmstream = init_vgmstream_ogg_vorbis_callbacks(sf, NULL, start_offset, &ovmi);
vgmstream = init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi);
}
#else
goto fail;

View File

@ -137,9 +137,11 @@ typedef struct {
off_t scd_xor_length;
uint32_t xor_value;
//ov_callbacks *callbacks
} ogg_vorbis_meta_info_t;
VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, ov_callbacks *callbacks, off_t start, const ogg_vorbis_meta_info_t *ovmi);
VGMSTREAM* init_vgmstream_ogg_vorbis_config(STREAMFILE *sf, off_t start, const ogg_vorbis_meta_info_t* ovmi);
#endif
VGMSTREAM * init_vgmstream_hca(STREAMFILE *streamFile);
@ -951,4 +953,6 @@ VGMSTREAM* init_vgmstream_ogv_3rdeye(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_sspr(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_piff_tpcm(STREAMFILE* sf);
#endif /*_META_H*/

View File

@ -10,12 +10,12 @@
#include "../coding/coding.h"
/* MOGG - Harmonix Music Systems (Guitar Hero)[Unencrypted Type] */
VGMSTREAM * init_vgmstream_mogg(STREAMFILE *streamFile) {
VGMSTREAM* init_vgmstream_mogg(STREAMFILE *sf) {
#ifdef VGM_USE_VORBIS
off_t start_offset;
/* checks */
if (!check_extensions(streamFile, "mogg"))
if (!check_extensions(sf, "mogg"))
goto fail;
{
@ -24,8 +24,8 @@ VGMSTREAM * init_vgmstream_mogg(STREAMFILE *streamFile) {
ovmi.meta_type = meta_MOGG;
start_offset = read_32bitLE(0x04, streamFile);
result = init_vgmstream_ogg_vorbis_callbacks(streamFile, NULL, start_offset, &ovmi);
start_offset = read_32bitLE(0x04, sf);
result = init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi);
if (result != NULL) {
return result;

View File

@ -163,11 +163,14 @@ fail:
#ifdef VGM_USE_FFMPEG
typedef struct {
int channels;
int sample_rate;
int32_t num_samples;
int loop_flag;
int32_t loop_start;
int32_t loop_end;
int32_t encoder_delay;
int subsongs;
} mp4_header;
static void parse_mp4(STREAMFILE* sf, mp4_header* mp4);
@ -199,36 +202,45 @@ VGMSTREAM* init_vgmstream_mp4_aac_ffmpeg(STREAMFILE* sf) {
parse_mp4(sf, &mp4);
/* most values aren't read directly and use FFmpeg b/c MP4 makes things hard */
if (!mp4.num_samples)
mp4.num_samples = ffmpeg_get_samples(ffmpeg_data); /* does this take into account encoder delay? see FFV */
if (!mp4.channels)
mp4.channels = ffmpeg_get_channels(ffmpeg_data);
if (!mp4.sample_rate)
mp4.sample_rate = ffmpeg_get_sample_rate(ffmpeg_data);
if (!mp4.subsongs)
mp4.subsongs = ffmpeg_get_subsong_count(ffmpeg_data); /* may contain N tracks */
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(ffmpeg_data->channels, mp4.loop_flag);
vgmstream = allocate_vgmstream(mp4.channels, mp4.loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_MP4;
vgmstream->sample_rate = ffmpeg_data->sampleRate;
vgmstream->sample_rate = mp4.sample_rate;
vgmstream->num_samples = mp4.num_samples;
if (vgmstream->num_samples == 0)
vgmstream->num_samples = ffmpeg_data->totalSamples;
vgmstream->loop_start_sample = mp4.loop_start;
vgmstream->loop_end_sample = mp4.loop_end;
vgmstream->codec_data = ffmpeg_data;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
vgmstream->num_streams = ffmpeg_data->streamCount; /* may contain N tracks */
vgmstream->num_streams = mp4.subsongs;
vgmstream->channel_layout = ffmpeg_get_channel_layout(vgmstream->codec_data);
if (mp4.encoder_delay)
ffmpeg_set_skip_samples(vgmstream->codec_data, mp4.encoder_delay);
vgmstream->channel_layout = ffmpeg_get_channel_layout(ffmpeg_data);
/* needed for CRI MP4, otherwise FFmpeg usually reads standard delay */
ffmpeg_set_skip_samples(vgmstream->codec_data, mp4.encoder_delay);
return vgmstream;
fail:
if (ffmpeg_data) {
free_ffmpeg(ffmpeg_data);
if (vgmstream) vgmstream->codec_data = NULL;
free_ffmpeg(ffmpeg_data);
if (vgmstream) {
vgmstream->codec_data = NULL;
close_vgmstream(vgmstream);
}
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}

View File

@ -108,7 +108,7 @@ VGMSTREAM* init_vgmstream_msf(STREAMFILE* sf) {
encoder_delay = 1024 + 69*2;
block_align = (codec==4 ? 0x60 : (codec==5 ? 0x98 : 0xC0)) * vgmstream->channels;
vgmstream->num_samples = atrac3_bytes_to_samples(data_size, block_align) - encoder_delay;
if (vgmstream->sample_rate == 0xFFFFFFFF) /* some MSFv1 (Digi World SP) */
if (vgmstream->sample_rate == -1) /* some MSFv1 (Digi World SP) */
vgmstream->sample_rate = 44100; /* voice tracks seems to use 44khz, not sure about other tracks */
vgmstream->codec_data = init_ffmpeg_atrac3_raw(sf, start_offset,data_size, vgmstream->num_samples,vgmstream->channels,vgmstream->sample_rate, block_align, encoder_delay);
@ -144,20 +144,16 @@ VGMSTREAM* init_vgmstream_msf(STREAMFILE* sf) {
}
#elif defined(VGM_USE_FFMPEG)
case 0x07: { /* MPEG (LAME MP3) [Dengeki Bunko Fighting Climax (PS3), Asura's Wrath (PS3)-vbr] */
ffmpeg_codec_data *ffmpeg_data = NULL;
int is_vbr = (flags & 0x20); /* must calc samples/loop offsets manually */
ffmpeg_data = init_ffmpeg_offset(sf, start_offset, sf->get_size(sf));
if (!ffmpeg_data) goto fail;
vgmstream->codec_data = ffmpeg_data;
vgmstream->codec_data = init_ffmpeg_offset(sf, start_offset, 0);;
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
//todo use same calcs as above
vgmstream->num_samples = (int64_t)data_size * ffmpeg_data->sampleRate * 8 / ffmpeg_data->bitrate;
if (loop_flag) {
vgmstream->loop_start_sample = (int64_t)loop_start * ffmpeg_data->sampleRate * 8 / ffmpeg_data->bitrate;
vgmstream->loop_end_sample = (int64_t)loop_end * ffmpeg_data->sampleRate * 8 / ffmpeg_data->bitrate;
}
vgmstream->num_samples = mpeg_get_samples_clean(sf, start_offset, data_size, &loop_start, &loop_end, is_vbr);
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = loop_end;
break;
}
#endif

View File

@ -1,79 +1,79 @@
#include "meta.h"
#include "../coding/coding.h"
/* .MUS - Vicious Cycle games [Dinotopia: The Sunstone Odyssey (GC/Xbox), Robotech: Battlecry (PS2/Xbox)] */
VGMSTREAM * init_vgmstream_mus_vc(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count, sample_rate;
int big_endian, type;
int32_t(*read_32bit)(off_t, STREAMFILE*) = NULL;
/* checks */
if (!check_extensions(streamFile, "mus"))
goto fail;
if (read_32bitBE(0x08,streamFile) != 0xBBBBBBBB &&
read_32bitBE(0x14,streamFile) != 0xBBBBBBBB &&
read_32bitBE(0x2c,streamFile) != 0xBEBEBEBE)
goto fail;
big_endian = (read_32bitBE(0x00,streamFile) == 0xFBBFFBBF);
read_32bit = big_endian ? read_32bitBE : read_32bitLE;
type = read_32bit(0x04, streamFile);
/* 0x08: pseudo size? */
/* other fields may be chunk sizes and lesser stuff */
/* 0x88: codec header */
channel_count = read_32bit(0x54,streamFile); /* assumed */
if (channel_count != 1) goto fail;
sample_rate = read_32bit(0x58,streamFile);
loop_flag = 1; /* most files repeat except small jingles, but smaller ambient tracks also repeat */
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_MUS_VC;
vgmstream->sample_rate = sample_rate;
switch(type) {
case 0x01:
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_none;
vgmstream->num_samples = dsp_bytes_to_samples(read_32bit(0xB0,streamFile), vgmstream->channels);
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = vgmstream->num_samples;
start_offset = 0xB8;
dsp_read_coefs_be(vgmstream,streamFile,0x88,0x00);
dsp_read_hist_be (vgmstream,streamFile,0xac,0x00);
break;
case 0x02:
vgmstream->coding_type = coding_XBOX_IMA;
vgmstream->layout_type = layout_none;
vgmstream->num_samples = xbox_ima_bytes_to_samples(read_32bit(0x9a,streamFile), vgmstream->channels);
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = vgmstream->num_samples;
start_offset = 0x9e;
break;
default:
goto fail;
}
read_string(vgmstream->stream_name,0x14, 0x34,streamFile); /* repeated at 0x64, size at 0x30/0x60 */
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
#include "meta.h"
#include "../coding/coding.h"
/* .MUS - Vicious Cycle games [Dinotopia: The Sunstone Odyssey (GC/Xbox), Robotech: Battlecry (PS2/Xbox)] */
VGMSTREAM* init_vgmstream_mus_vc(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
int loop_flag, channels, sample_rate;
int big_endian, type;
int32_t(*read_32bit)(off_t, STREAMFILE*) = NULL;
/* checks */
if (!check_extensions(sf, "mus"))
goto fail;
if (read_u32be(0x08,sf) != 0xBBBBBBBB &&
read_u32be(0x14,sf) != 0xBBBBBBBB &&
read_u32be(0x2c,sf) != 0xBEBEBEBE)
goto fail;
big_endian = (read_u32be(0x00,sf) == 0xFBBFFBBF);
read_32bit = big_endian ? read_32bitBE : read_32bitLE;
type = read_32bit(0x04, sf);
/* 0x08: pseudo size? */
/* other fields may be chunk sizes and lesser stuff */
/* 0x88: codec header */
channels = read_32bit(0x54,sf); /* assumed */
if (channels != 1) goto fail;
sample_rate = read_32bit(0x58,sf);
loop_flag = 1; /* most files repeat except small jingles, but smaller ambient tracks also repeat */
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_MUS_VC;
vgmstream->sample_rate = sample_rate;
switch(type) {
case 0x01:
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_none;
vgmstream->num_samples = dsp_bytes_to_samples(read_32bit(0xB0,sf), vgmstream->channels);
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = vgmstream->num_samples;
start_offset = 0xB8;
dsp_read_coefs_be(vgmstream,sf,0x88,0x00);
dsp_read_hist_be (vgmstream,sf,0xac,0x00);
break;
case 0x02:
vgmstream->coding_type = coding_XBOX_IMA;
vgmstream->layout_type = layout_none;
vgmstream->num_samples = xbox_ima_bytes_to_samples(read_32bit(0x9a,sf), vgmstream->channels);
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = vgmstream->num_samples;
start_offset = 0x9e;
break;
default:
goto fail;
}
read_string(vgmstream->stream_name,0x14, 0x34,sf); /* repeated at 0x64, size at 0x30/0x60 */
if (!vgmstream_open_stream(vgmstream,sf,start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -6,7 +6,7 @@
VGMSTREAM* init_vgmstream_naac(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
int loop_flag, channels;
int loop_flag, channels, skip_samples;
size_t data_size;
@ -22,6 +22,7 @@ VGMSTREAM* init_vgmstream_naac(STREAMFILE* sf) {
start_offset = 0x1000;
loop_flag = (read_s32le(0x18,sf) != 0);
channels = read_s32le(0x08,sf);
skip_samples = 1024; /* raw AAC doesn't set this */
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
@ -42,15 +43,14 @@ VGMSTREAM* init_vgmstream_naac(STREAMFILE* sf) {
#ifdef VGM_USE_FFMPEG
{
vgmstream->codec_data = init_ffmpeg_aac(sf, start_offset, data_size);
vgmstream->codec_data = init_ffmpeg_aac(sf, start_offset, data_size, skip_samples);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
/* observed default, some files start without silence though seems correct when loop_start=0 */
ffmpeg_set_skip_samples(vgmstream->codec_data, 1024); /* raw AAC doesn't set this */
vgmstream->num_samples -= 1024;
vgmstream->loop_end_sample -= 1024;
vgmstream->num_samples -= skip_samples;
vgmstream->loop_end_sample -= skip_samples;
/* for some reason last frame is ignored/bugged in various decoders (gives EOF errors) */
}
#else

View File

@ -1,46 +1,46 @@
#include "meta.h"
#include "../coding/coding.h"
/* .str - Cauldron/Conan mini-header + interleaved dsp data [Conan (GC)] */
VGMSTREAM * init_vgmstream_ngc_str(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int channel_count, loop_flag;
/* checks */
if (!check_extensions(streamFile, "str"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0xFAAF0001) /* header id */
goto fail;
channel_count = 2; /* always loop & stereo */
loop_flag = 1;
start_offset = 0x60;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = read_32bitBE(0x04,streamFile);
vgmstream->num_samples = read_32bitBE(0x08,streamFile);
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = vgmstream->num_samples;
vgmstream->meta_type = meta_DSP_STR;
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = read_32bitBE(0x0C,streamFile);
dsp_read_coefs_be(vgmstream, streamFile, 0x10, 0x20);
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
#include "meta.h"
#include "../coding/coding.h"
/* .str - Cauldron/Conan mini-header + interleaved dsp data [Conan (GC)] */
VGMSTREAM* init_vgmstream_ngc_str(STREAMFILE *sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
int channels, loop_flag;
/* checks */
if (!check_extensions(sf, "str"))
goto fail;
if (read_u32be(0x00,sf) != 0xFAAF0001) /* header id */
goto fail;
channels = 2; /* always loop & stereo */
loop_flag = 1;
start_offset = 0x60;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels,loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = read_s32be(0x04,sf);
vgmstream->num_samples = read_s32be(0x08,sf);
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = vgmstream->num_samples;
vgmstream->meta_type = meta_DSP_STR;
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = read_u32be(0x0C,sf);
dsp_read_coefs_be(vgmstream, sf, 0x10, 0x20);
if (!vgmstream_open_stream(vgmstream,sf,start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -62,6 +62,7 @@ static STREAMFILE* setup_nus3bank_streamfile(STREAMFILE *sf, off_t start) {
/* find "data" */
pos = 0x0c;
data_pos = 0;
while(pos < sizeof(buf)) {
chunk_type = get_u32be(buf + pos + 0x00) ^ chunk_key;
chunk_size = get_u32be(buf + pos + 0x04) ^ chunk_key;

View File

@ -1,57 +1,57 @@
#include "meta.h"
#include "../coding/coding.h"
/* NWAV - from Chunsoft games [Fuurai no Shiren Gaiden: Onnakenshi Asuka Kenzan! (PC)] */
VGMSTREAM * init_vgmstream_nwav(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
/* checks */
/* .nwav: header id (no filenames in bigfiles) */
if ( !check_extensions(streamFile,"nwav") )
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x4E574156) /* "NWAV" */
goto fail;
#ifdef VGM_USE_VORBIS
{
ogg_vorbis_meta_info_t ovmi = {0};
int channels;
/* 0x04: version? */
/* 0x08: crc? */
ovmi.stream_size = read_32bitLE(0x0c, streamFile);
ovmi.loop_end = read_32bitLE(0x10, streamFile); /* num_samples, actually */
/* 0x14: sample rate */
/* 0x18: bps? (16) */
channels = read_8bit(0x19, streamFile);
start_offset = read_16bitLE(0x1a, streamFile);
ovmi.loop_flag = read_16bitLE(0x1c, streamFile) != 0; /* loop count? -1 = loops */
/* 0x1e: always 2? */
/* 0x20: always 1? */
ovmi.loop_start = read_32bitLE(0x24, streamFile);
/* 0x28: always 1? */
/* 0x2a: always 1? */
/* 0x2c: always null? */
ovmi.meta_type = meta_NWAV;
/* values are in resulting bytes */
ovmi.loop_start = ovmi.loop_start / sizeof(int16_t) / channels;
ovmi.loop_end = ovmi.loop_end / sizeof(int16_t) / channels;
vgmstream = init_vgmstream_ogg_vorbis_callbacks(streamFile, NULL, start_offset, &ovmi);
}
#else
goto fail;
#endif
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
#include "meta.h"
#include "../coding/coding.h"
/* NWAV - from Chunsoft games [Fuurai no Shiren Gaiden: Onnakenshi Asuka Kenzan! (PC)] */
VGMSTREAM * init_vgmstream_nwav(STREAMFILE *sf) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
/* checks */
/* .nwav: header id (no filenames in bigfiles) */
if ( !check_extensions(sf,"nwav") )
goto fail;
if (read_32bitBE(0x00,sf) != 0x4E574156) /* "NWAV" */
goto fail;
#ifdef VGM_USE_VORBIS
{
ogg_vorbis_meta_info_t ovmi = {0};
int channels;
/* 0x04: version? */
/* 0x08: crc? */
ovmi.stream_size = read_32bitLE(0x0c, sf);
ovmi.loop_end = read_32bitLE(0x10, sf); /* num_samples, actually */
/* 0x14: sample rate */
/* 0x18: bps? (16) */
channels = read_8bit(0x19, sf);
start_offset = read_16bitLE(0x1a, sf);
ovmi.loop_flag = read_16bitLE(0x1c, sf) != 0; /* loop count? -1 = loops */
/* 0x1e: always 2? */
/* 0x20: always 1? */
ovmi.loop_start = read_32bitLE(0x24, sf);
/* 0x28: always 1? */
/* 0x2a: always 1? */
/* 0x2c: always null? */
ovmi.meta_type = meta_NWAV;
/* values are in resulting bytes */
ovmi.loop_start = ovmi.loop_start / sizeof(int16_t) / channels;
ovmi.loop_end = ovmi.loop_end / sizeof(int16_t) / channels;
vgmstream = init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi);
}
#else
goto fail;
#endif
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -286,21 +286,21 @@ VGMSTREAM* init_vgmstream_ogg_vorbis(STREAMFILE* sf) {
* 0x0c(2): PCM block size, 0x0e(2): PCM bps, 0x10: null, 0x18: samples (in PCM bytes)
* - .isl: looping table (encrypted like the files) */
if (isl_name) {
STREAMFILE* islFile = NULL;
STREAMFILE* sf_isl = NULL;
islFile = open_streamfile_by_filename(sf, isl_name);
sf_isl = open_streamfile_by_filename(sf, isl_name);
if (!islFile) {
if (!sf_isl) {
/* try in ../(file) too since that's how the .isl is stored on disc */
char isl_path[PATH_LIMIT];
snprintf(isl_path, sizeof(isl_path), "../%s", isl_name);
islFile = open_streamfile_by_filename(sf, isl_path);
sf_isl = open_streamfile_by_filename(sf, isl_path);
}
if (islFile) {
if (sf_isl) {
STREAMFILE* dec_sf = NULL;
dec_sf = setup_ogg_vorbis_streamfile(islFile, cfg);
dec_sf = setup_ogg_vorbis_streamfile(sf_isl, cfg);
if (dec_sf) {
off_t loop_offset;
char basename[PATH_LIMIT];
@ -327,7 +327,7 @@ VGMSTREAM* init_vgmstream_ogg_vorbis(STREAMFILE* sf) {
close_streamfile(dec_sf);
}
close_streamfile(islFile);
close_streamfile(sf_isl);
}
}
}
@ -367,7 +367,7 @@ VGMSTREAM* init_vgmstream_ogg_vorbis(STREAMFILE* sf) {
}
if (is_lse) { /* [Nippon Ichi PC games] */
if (read_32bitBE(0x00,sf) == 0xFFFFFFFF) { /* [Operation Abyss: New Tokyo Legacy (PC)] */
if (read_u32be(0x00,sf) == 0xFFFFFFFF) { /* [Operation Abyss: New Tokyo Legacy (PC)] */
cfg.key[0] = 0xFF;
cfg.key_len = 1;
cfg.is_header_swap = 1;
@ -416,7 +416,7 @@ VGMSTREAM* init_vgmstream_ogg_vorbis(STREAMFILE* sf) {
ovmi.meta_type = meta_OGG_VORBIS;
}
vgmstream = init_vgmstream_ogg_vorbis_callbacks(temp_sf != NULL ? temp_sf : sf, NULL, start_offset, &ovmi);
vgmstream = init_vgmstream_ogg_vorbis_config(temp_sf != NULL ? temp_sf : sf, start_offset, &ovmi);
close_streamfile(temp_sf);
return vgmstream;
@ -426,7 +426,7 @@ fail:
return NULL;
}
VGMSTREAM* init_vgmstream_ogg_vorbis_callbacks(STREAMFILE* sf, ov_callbacks* callbacks, off_t start, const ogg_vorbis_meta_info_t *ovmi) {
VGMSTREAM* init_vgmstream_ogg_vorbis_config(STREAMFILE* sf, off_t start, const ogg_vorbis_meta_info_t* ovmi) {
VGMSTREAM* vgmstream = NULL;
ogg_vorbis_codec_data* data = NULL;
ogg_vorbis_io io = {0};

View File

@ -27,7 +27,7 @@ VGMSTREAM* init_vgmstream_ogv_3rdeye(STREAMFILE* sf) {
ovmi.meta_type = meta_OGV_3RDEYE;
ovmi.stream_size = subfile_size;
vgmstream = init_vgmstream_ogg_vorbis_callbacks(sf, NULL, subfile_offset, &ovmi);
vgmstream = init_vgmstream_ogg_vorbis_config(sf, subfile_offset, &ovmi);
}
#else
goto fail;

View File

@ -157,16 +157,16 @@ VGMSTREAM* init_vgmstream_opus_n1(STREAMFILE* sf) {
int num_samples, loop_start, loop_end;
/* checks */
if ( !check_extensions(sf,"opus,lopus"))
if (!check_extensions(sf,"opus,lopus"))
goto fail;
if (!((read_32bitBE(0x04,sf) == 0x00000000 && read_32bitBE(0x0c,sf) == 0x00000000) ||
(read_32bitBE(0x04,sf) == 0xFFFFFFFF && read_32bitBE(0x0c,sf) == 0xFFFFFFFF)))
if (!((read_u32be(0x04,sf) == 0x00000000 && read_u32be(0x0c,sf) == 0x00000000) ||
(read_u32be(0x04,sf) == 0xFFFFFFFF && read_u32be(0x0c,sf) == 0xFFFFFFFF)))
goto fail;
offset = 0x10;
num_samples = 0;
loop_start = read_32bitLE(0x00,sf);
loop_end = read_32bitLE(0x08,sf);
loop_start = read_s32le(0x00,sf);
loop_end = read_s32le(0x08,sf);
return init_vgmstream_opus(sf, meta_OPUS, offset, num_samples,loop_start,loop_end);
fail:

View File

@ -0,0 +1,54 @@
#include "meta.h"
#include "../coding/coding.h"
/* PIFF TADH - from Tantalus games [House of the Dead (SAT)] */
VGMSTREAM* init_vgmstream_piff_tpcm(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset, header_offset, data_size;
int loop_flag, channels, sample_rate;
/* checks */
/* .tad: from internal filenames */
if (!check_extensions(sf, "tad"))
goto fail;
/* Tantalus also has PIFF without this */
if (!is_id32be(0x00,sf, "PIFF") || !is_id32be(0x08,sf, "TPCM") || !is_id32be(0x0c,sf, "TADH"))
goto fail;
header_offset = 0x14;
/* 0x00: 1? */
/* 0x01: 1? */
channels = read_u16le(header_offset + 0x02,sf);
sample_rate = read_s32le(header_offset + 0x04,sf);
/* 0x08+: ? (mostly fixed, maybe related to ADPCM?) */
loop_flag = 0;
if (!is_id32be(0x38,sf, "BODY"))
goto fail;
start_offset = 0x40;
data_size = read_u32le(0x3c,sf);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_PIFF_TPCM;
vgmstream->sample_rate = sample_rate;
vgmstream->coding_type = coding_TANTALUS;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x10;
vgmstream->num_samples = tantalus_bytes_to_samples(data_size, channels);
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -1,64 +1,53 @@
#include "meta.h"
#include "../util.h"
#include "../coding/coding.h"
/* SFS (from Baroque) */
VGMSTREAM * init_vgmstream_sfs(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
/* SFS - from Sting games [Baroque (PS2)] */
VGMSTREAM* init_vgmstream_sfs(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
int loop_flag;
int channel_count;
int loop_flag, channels, sample_rate;
size_t channel_size, loop_start;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("sfs",filename_extension(filename))) goto fail;
/* check header */
if (read_32bitBE(0x00,streamFile) != 0x53544552) /* "STER" */
/* checks */
/* .sfs: bigfile extension (no apparent names) */
if (!check_extensions(sf, "sfs"))
goto fail;
loop_flag = (read_32bitLE(0x08,streamFile)!=0xFFFFFFFF);
channel_count = 2;
if (!is_id32be(0x00,sf, "STER"))
goto fail;
channel_size = read_u32le(0x04, sf);
loop_start = read_u32le(0x08, sf); /* absolute (ex. offset 0x50 for full loops) */
/* 0x0c: data size BE */
sample_rate = read_s32be(0x10,sf);
loop_flag = loop_start != 0xFFFFFFFF;
channels = 2;
start_offset = 0x30;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
start_offset = 0x30;
vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitBE(0x10,streamFile);
vgmstream->coding_type = coding_PSX;
vgmstream->num_samples = (read_32bitLE(0x04,streamFile)*2)*28/16/channel_count;
if (loop_flag) {
vgmstream->loop_start_sample = read_32bitLE(0x08,streamFile)*28/16/channel_count;
vgmstream->loop_end_sample = (read_32bitLE(0x04,streamFile)*2)*28/16/channel_count;
}
vgmstream->meta_type = meta_SFS;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = ps_bytes_to_samples(channel_size, 1);
vgmstream->loop_start_sample = ps_bytes_to_samples(loop_start - start_offset, channels);
vgmstream->loop_end_sample = vgmstream->num_samples;
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x10;
vgmstream->meta_type = meta_SFS;
/* 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;
}
}
read_string(vgmstream->stream_name,0x10+1, 0x20,sf);
if (!vgmstream_open_stream(vgmstream, sf, 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

@ -3,43 +3,43 @@
/* .VAS - from Konami Jikkyou Powerful Pro Yakyuu games */
VGMSTREAM * init_vgmstream_ps2_vas(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
VGMSTREAM* init_vgmstream_ps2_vas(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count;
int loop_flag, channels;
/* checks */
if (!check_extensions(streamFile, "vas"))
if (!check_extensions(sf, "vas"))
goto fail;
if (read_32bitLE(0x00,streamFile) + 0x800 != get_streamfile_size(streamFile))
if (read_u32le(0x00,sf) + 0x800 != get_streamfile_size(sf))
goto fail;
loop_flag = (read_32bitLE(0x10,streamFile) != 0);
channel_count = 2;
loop_flag = (read_u32le(0x10,sf) != 0);
channels = 2;
start_offset = 0x800;
/* header is too simple so test a bit */
if (!ps_check_format(streamFile, start_offset, 0x1000))
if (!ps_check_format(sf, start_offset, 0x1000))
goto fail;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
vgmstream = allocate_vgmstream(channels,loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_PS2_VAS;
vgmstream->sample_rate = read_32bitLE(0x04,streamFile);
vgmstream->sample_rate = read_s32le(0x04,sf);
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x200;
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->num_samples = ps_bytes_to_samples(read_u32le(0x00,sf), channels);
vgmstream->loop_start_sample = ps_bytes_to_samples(read_u32le(0x14,sf), channels);
vgmstream->loop_end_sample = vgmstream->num_samples;
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
@ -50,35 +50,35 @@ fail:
/* .VAS in containers */
VGMSTREAM * init_vgmstream_ps2_vas_container(STREAMFILE *streamFile) {
VGMSTREAM *vgmstream = NULL;
STREAMFILE *temp_streamFile = NULL;
VGMSTREAM* init_vgmstream_ps2_vas_container(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
STREAMFILE* temp_sf = NULL;
off_t subfile_offset = 0;
size_t subfile_size = 0;
int total_subsongs, target_subsong = streamFile->stream_index;
int total_subsongs, target_subsong = sf->stream_index;
/* checks */
if (!check_extensions(streamFile, "vas"))
if (!check_extensions(sf, "vas"))
goto fail;
if (read_32bitBE(0x00, streamFile) == 0xAB8A5A00) { /* fixed value */
if (read_u32be(0x00, sf) == 0xAB8A5A00) { /* fixed value */
/* just in case */
if (read_32bitLE(0x04, streamFile)*0x800 + 0x800 != get_streamfile_size(streamFile))
if (read_u32le(0x04, sf) * 0x800 + 0x800 != get_streamfile_size(sf))
goto fail;
total_subsongs = read_32bitLE(0x08, streamFile); /* also at 0x10 */
total_subsongs = read_s32le(0x08, sf); /* also at 0x10 */
if (target_subsong == 0) target_subsong = 1;
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
/* check offset table flag, 0x98 has table size */
if (read_32bitLE(0x94, streamFile)) {
if (read_32bitLE(0x94, sf)) {
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;
subfile_offset = read_32bitLE(header_offset + 0x00,sf) * 0x800;
subfile_size = read_32bitLE(header_offset + 0x08,sf) + 0x800;
}
else {
/* a bunch of files */
@ -86,7 +86,7 @@ VGMSTREAM * init_vgmstream_ps2_vas_container(STREAMFILE *streamFile) {
int i;
for (i = 0; i < total_subsongs; i++) {
size_t size = read_32bitLE(offset, streamFile) + 0x800;
size_t size = read_32bitLE(offset, sf) + 0x800;
if (i + 1 == target_subsong) {
subfile_offset = offset;
@ -102,18 +102,18 @@ VGMSTREAM * init_vgmstream_ps2_vas_container(STREAMFILE *streamFile) {
}
else {
/* some .vas are just files pasted together, better extracted externally but whatevs */
size_t file_size = get_streamfile_size(streamFile);
size_t file_size = get_streamfile_size(sf);
off_t offset = 0;
/* must have multiple .vas */
if (read_32bitLE(0x00,streamFile) + 0x800 >= file_size)
if (read_32bitLE(0x00,sf) + 0x800 >= file_size)
goto fail;
total_subsongs = 0;
if (target_subsong == 0) target_subsong = 1;
while (offset < file_size) {
size_t size = read_32bitLE(offset,streamFile) + 0x800;
size_t size = read_32bitLE(offset,sf) + 0x800;
/* some files can be null, ignore */
if (size > 0x800) {
@ -136,19 +136,19 @@ VGMSTREAM * init_vgmstream_ps2_vas_container(STREAMFILE *streamFile) {
}
temp_streamFile = setup_subfile_streamfile(streamFile, subfile_offset,subfile_size, NULL);
if (!temp_streamFile) goto fail;
temp_sf = setup_subfile_streamfile(sf, subfile_offset,subfile_size, NULL);
if (!temp_sf) goto fail;
vgmstream = init_vgmstream_ps2_vas(temp_streamFile);
vgmstream = init_vgmstream_ps2_vas(temp_sf);
if (!vgmstream) goto fail;
vgmstream->num_streams = total_subsongs;
close_streamfile(temp_streamFile);
close_streamfile(temp_sf);
return vgmstream;
fail:
close_streamfile(temp_streamFile);
close_streamfile(temp_sf);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -294,7 +294,7 @@ fail:
return 0;
}
static int is_ue4_msadpcm(VGMSTREAM* vgmstream, STREAMFILE* sf, riff_fmt_chunk* fmt, int fact_sample_count, off_t start_offset);
static int is_ue4_msadpcm(STREAMFILE* sf, riff_fmt_chunk* fmt, int fact_sample_count, off_t start_offset);
static size_t get_ue4_msadpcm_interleave(STREAMFILE* sf, riff_fmt_chunk* fmt, off_t start, size_t size);
@ -604,10 +604,10 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) {
/* ignore Beyond Good & Evil HD PS3 evil reuse of PCM codec */
if (fmt.coding_type == coding_PCM16LE &&
read_32bitBE(start_offset+0x00, sf) == 0x4D534643 && /* "MSF\43" */
read_32bitBE(start_offset+0x34, sf) == 0xFFFFFFFF && /* always */
read_32bitBE(start_offset+0x38, sf) == 0xFFFFFFFF &&
read_32bitBE(start_offset+0x3c, sf) == 0xFFFFFFFF)
read_u32be(start_offset+0x00, sf) == 0x4D534643 && /* "MSF\43" */
read_u32be(start_offset+0x34, sf) == 0xFFFFFFFF && /* always */
read_u32be(start_offset+0x38, sf) == 0xFFFFFFFF &&
read_u32be(start_offset+0x3c, sf) == 0xFFFFFFFF)
goto fail;
/* ignore Gitaroo Man Live! (PSP) multi-RIFF (to allow chunked TXTH) */
@ -795,7 +795,7 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) {
}
/* UE4 uses interleaved mono MSADPCM, try to autodetect without breaking normal MSADPCM */
if (fmt.coding_type == coding_MSADPCM && is_ue4_msadpcm(vgmstream, sf, &fmt, fact_sample_count, start_offset)) {
if (fmt.coding_type == coding_MSADPCM && is_ue4_msadpcm(sf, &fmt, fact_sample_count, start_offset)) {
vgmstream->coding_type = coding_MSADPCM_int;
vgmstream->codec_config = 1; /* mark as UE4 MSADPCM */
vgmstream->frame_size = fmt.block_size;
@ -850,6 +850,8 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) {
vgmstream->loop_start_sample = pcm_bytes_to_samples(loop_start_nxbf, vgmstream->channels, 16);
vgmstream->loop_end_sample = vgmstream->num_samples;
break;
default:
break;
}
}
}
@ -868,7 +870,7 @@ fail:
}
/* UE4 MSADPCM is quite normal but has a few minor quirks we can use to detect it */
static int is_ue4_msadpcm(VGMSTREAM* vgmstream, STREAMFILE* sf, riff_fmt_chunk* fmt, int fact_sample_count, off_t start) {
static int is_ue4_msadpcm(STREAMFILE* sf, riff_fmt_chunk* fmt, int fact_sample_count, off_t start) {
/* multichannel ok */
if (fmt->channel_count < 2)

View File

@ -1,115 +1,117 @@
#include "meta.h"
#include "../coding/coding.h"
/* RKV - from Legacy of Kain - Blood Omen 2 (PS2) */
VGMSTREAM * init_vgmstream_ps2_rkv(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset, header_offset;
size_t data_size;
int loop_flag, channel_count;
/* checks */
if (!check_extensions(streamFile, "rkv"))
goto fail;
if (read_32bitBE(0x24,streamFile) != 0x00) /* quick test vs GC rkv (coef position) */
goto fail;
/* some RKV got info at offset 0x00, some other at 0x0 4 */
if (read_32bitLE(0x00,streamFile)==0)
header_offset = 0x04;
else
header_offset = 0x00;
switch (read_32bitLE(header_offset+0x0c,streamFile)) {
case 0x00: channel_count = 1; break;
case 0x01: channel_count = 2; break;
default: goto fail;
}
loop_flag = (read_32bitLE(header_offset+0x04,streamFile) != 0xFFFFFFFF);
start_offset = 0x800;
data_size = get_streamfile_size(streamFile) - start_offset;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = read_32bitLE(header_offset,streamFile);
vgmstream->num_samples = ps_bytes_to_samples(data_size, channel_count);
//vgmstream->num_samples = read_32bitLE(header_offset+0x08,streamFile); /* sometimes not set */
if (loop_flag) {
vgmstream->loop_start_sample = read_32bitLE(header_offset+0x04,streamFile);
vgmstream->loop_end_sample = read_32bitLE(header_offset+0x08,streamFile);
}
vgmstream->meta_type = meta_PS2_RKV;
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x400;
if (vgmstream->interleave_block_size)
vgmstream->interleave_last_block_size = (data_size % (vgmstream->interleave_block_size*vgmstream->channels)) / vgmstream->channels;
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
/* RKV - from Legacy of Kain - Blood Omen 2 (GC) */
VGMSTREAM * init_vgmstream_ngc_rkv(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count;
/* checks */
/* "": empty (files have names but no extensions), .rkv: container bigfile extension, .bo2: fake extension */
if (!check_extensions(streamFile, ",rkv,bo2"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x00)
goto fail;
if (read_32bitBE(0x24,streamFile) == 0x00) /* quick test vs GC rkv (coef position) */
goto fail;
switch (read_32bitBE(0x10,streamFile)) {
case 0x00: channel_count = 1; break;
case 0x01: channel_count = 2; break;
default: goto fail;
}
loop_flag = (read_32bitBE(0x08,streamFile) != 0xFFFFFFFF);
start_offset = 0x800;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = read_32bitBE(0x04,streamFile);
vgmstream->num_samples = read_32bitBE(0x0C,streamFile);
if (loop_flag) {
vgmstream->loop_start_sample = read_32bitBE(0x08,streamFile);
vgmstream->loop_end_sample = read_32bitBE(0x0C,streamFile);
}
vgmstream->meta_type = meta_NGC_RKV;
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x400;
dsp_read_coefs_be(vgmstream,streamFile,0x24,0x2e);
/* hist at 0x44/0x72? */
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
#include "meta.h"
#include "../coding/coding.h"
/* RKV - from Legacy of Kain - Blood Omen 2 (PS2) */
VGMSTREAM* init_vgmstream_ps2_rkv(STREAMFILE *sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset, header_offset;
size_t data_size;
int loop_flag, channels;
/* checks */
if (!check_extensions(sf, "rkv"))
goto fail;
if (read_u32be(0x24,sf) != 0x00) /* quick test vs GC rkv (coef position) */
goto fail;
/* some RKV got info at offset 0x00, some other at 0x0 4 */
if (read_u32le(0x00,sf) == 0)
header_offset = 0x04;
else
header_offset = 0x00;
switch (read_u32le(header_offset+0x0c,sf)) {
case 0x00: channels = 1; break;
case 0x01: channels = 2; break;
default: goto fail;
}
loop_flag = (read_u32le(header_offset+0x04,sf) != 0xFFFFFFFF);
start_offset = 0x800;
data_size = get_streamfile_size(sf) - start_offset;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels,loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = read_s32le(header_offset,sf);
vgmstream->num_samples = ps_bytes_to_samples(data_size, channels);
//vgmstream->num_samples = read_32bitLE(header_offset+0x08,sf); /* sometimes not set */
if (loop_flag) {
vgmstream->loop_start_sample = read_s32le(header_offset+0x04,sf);
vgmstream->loop_end_sample = read_s32le(header_offset+0x08,sf);
}
vgmstream->meta_type = meta_PS2_RKV;
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x400;
if (vgmstream->interleave_block_size)
vgmstream->interleave_last_block_size = (data_size % (vgmstream->interleave_block_size*vgmstream->channels)) / vgmstream->channels;
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
/* RKV - from Legacy of Kain - Blood Omen 2 (GC) */
VGMSTREAM* init_vgmstream_ngc_rkv(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
int loop_flag, channels;
/* checks */
/* "": empty (files have names but no extensions)
* .rkv: container bigfile extension
* .bo2: fake extension */
if (!check_extensions(sf, ",rkv,bo2"))
goto fail;
if (read_u32be(0x00,sf) != 0x00)
goto fail;
if (read_u32be(0x24,sf) == 0x00) /* quick test vs GC rkv (coef position) */
goto fail;
switch (read_u32be(0x10,sf)) {
case 0x00: channels = 1; break;
case 0x01: channels = 2; break;
default: goto fail;
}
loop_flag = (read_u32be(0x08,sf) != 0xFFFFFFFF);
start_offset = 0x800;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels,loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = read_s32be(0x04,sf);
vgmstream->num_samples = read_s32be(0x0C,sf);
if (loop_flag) {
vgmstream->loop_start_sample = read_s32be(0x08,sf);
vgmstream->loop_end_sample = read_s32be(0x0C,sf);
}
vgmstream->meta_type = meta_NGC_RKV;
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x400;
dsp_read_coefs_be(vgmstream,sf,0x24,0x2e);
/* hist at 0x44/0x72? */
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -3,11 +3,11 @@
/* RSD - from Radical Entertainment games */
VGMSTREAM * init_vgmstream_rsd(STREAMFILE *sf) {
VGMSTREAM * vgmstream = NULL;
VGMSTREAM* init_vgmstream_rsd(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset, name_offset;
size_t data_size;
int loop_flag, channel_count, sample_rate, interleave;
int loop_flag, channels, sample_rate, interleave;
uint32_t codec;
uint8_t version;
@ -15,22 +15,22 @@ VGMSTREAM * init_vgmstream_rsd(STREAMFILE *sf) {
/* checks */
if (!check_extensions(sf,"rsd,rsp"))
goto fail;
if ((read_32bitBE(0x00,sf) & 0xFFFFFF00) != 0x52534400) /* "RSD\00" */
if ((read_u32be(0x00,sf) & 0xFFFFFF00) != 0x52534400) /* "RSD\00" */
goto fail;
loop_flag = 0;
codec = (uint32_t)read_32bitBE(0x04,sf);
channel_count = read_32bitLE(0x08, sf);
codec = read_u32be(0x04,sf);
channels = read_s32le(0x08, sf);
/* 0x0c: always 16? */
sample_rate = read_32bitLE(0x10, sf);
sample_rate = read_s32le(0x10, sf);
version = read_8bit(0x03, sf);
switch(version) {
case '2': /* known codecs: VAG/XADP/PCMB [The Simpsons: Road Rage] */
case '3': /* known codecs: VAG/PCM/PCMB/GADP? [Dark Summit] */
interleave = read_32bitLE(0x14,sf); /* VAG only, 0x04 otherwise */
start_offset = read_32bitLE(0x18,sf);
interleave = read_u32le(0x14,sf); /* VAG only, 0x04 otherwise */
start_offset = read_u32le(0x18,sf);
name_offset = 0;
break;
@ -42,8 +42,8 @@ VGMSTREAM * init_vgmstream_rsd(STREAMFILE *sf) {
name_offset = 0;
/* PCMB/PCM/GADP normally start early but sometimes have padding [The Simpsons: Hit & Run (GC/Xbox)] */
if ((codec == 0x50434D20 || codec == 0x550434D42 || codec == 0x47414450)
&& read_32bitLE(0x80,sf) != 0x2D2D2D2D)
if ((codec == get_id32be("PCM ") || codec == get_id32be("PCMB") || codec == get_id32be("GADP"))
&& read_u32le(0x80,sf) != 0x2D2D2D2D)
start_offset = 0x80;
break;
@ -62,7 +62,7 @@ VGMSTREAM * init_vgmstream_rsd(STREAMFILE *sf) {
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
vgmstream = allocate_vgmstream(channels,loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_RSD;
@ -74,7 +74,7 @@ VGMSTREAM * init_vgmstream_rsd(STREAMFILE *sf) {
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x2;
vgmstream->num_samples = pcm_bytes_to_samples(data_size, channel_count, 16);
vgmstream->num_samples = pcm_bytes_to_samples(data_size, channels, 16);
break;
case 0x50434D42: /* "PCMB" [The Simpsons: Road Rage (GC), Dark Summit (GC)] */
@ -82,7 +82,7 @@ VGMSTREAM * init_vgmstream_rsd(STREAMFILE *sf) {
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x2;
vgmstream->num_samples = pcm_bytes_to_samples(data_size, channel_count, 16);
vgmstream->num_samples = pcm_bytes_to_samples(data_size, channels, 16);
break;
case 0x56414720: /* "VAG " [The Simpsons: Road Rage (PS2), Crash Tag Team Racing (PSP)] */
@ -90,11 +90,11 @@ VGMSTREAM * init_vgmstream_rsd(STREAMFILE *sf) {
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = (interleave == 0) ? 0x10 : interleave;
vgmstream->num_samples = ps_bytes_to_samples(data_size, channel_count);
vgmstream->num_samples = ps_bytes_to_samples(data_size, channels);
break;
case 0x58414450: /* "XADP" [The Simpsons: Road Rage (Xbox)], Crash Tag Team Racing (Xbox)] */
vgmstream->coding_type = (channel_count > 2) ? coding_XBOX_IMA_mch : coding_XBOX_IMA;
vgmstream->coding_type = (channels > 2) ? coding_XBOX_IMA_mch : coding_XBOX_IMA;
vgmstream->layout_type = layout_none;
vgmstream->num_samples = xbox_ima_bytes_to_samples(data_size, vgmstream->channels);
@ -107,7 +107,7 @@ VGMSTREAM * init_vgmstream_rsd(STREAMFILE *sf) {
dsp_read_coefs_le(vgmstream,sf,0x14,0x2e); /* LE! */
dsp_read_hist_le (vgmstream,sf,0x38,0x2e);
vgmstream->num_samples = dsp_bytes_to_samples(data_size, channel_count);
vgmstream->num_samples = dsp_bytes_to_samples(data_size, channels);
break;
case 0x57414450: /* "WADP" [Crash: Mind Over Mutant (Wii)] */
@ -117,15 +117,15 @@ VGMSTREAM * init_vgmstream_rsd(STREAMFILE *sf) {
dsp_read_coefs_be(vgmstream,sf,0x1a4,0x28);
dsp_read_hist_be (vgmstream,sf,0x1c8,0x28);
vgmstream->num_samples = dsp_bytes_to_samples(data_size, channel_count);
vgmstream->num_samples = dsp_bytes_to_samples(data_size, channels);
break;
case 0x52414450: /* "RADP" [The Simpsons: Hit & Run (GC), Scarface (Wii)] */
vgmstream->coding_type = coding_RAD_IMA;
vgmstream->layout_type = layout_none;
vgmstream->interleave_block_size = 0x14*channel_count;
vgmstream->interleave_block_size = 0x14*channels;
vgmstream->num_samples = data_size / 0x14 / channel_count * 32; /* bytes-to-samples */
vgmstream->num_samples = data_size / 0x14 / channels * 32; /* bytes-to-samples */
break;
#ifdef VGM_USE_VORBIS
@ -134,7 +134,7 @@ VGMSTREAM * init_vgmstream_rsd(STREAMFILE *sf) {
ovmi.meta_type = meta_RSD;
close_vgmstream(vgmstream);
vgmstream = init_vgmstream_ogg_vorbis_callbacks(sf, NULL, start_offset, &ovmi);
vgmstream = init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi);
if (!vgmstream) goto fail;
break;
}
@ -142,17 +142,15 @@ VGMSTREAM * init_vgmstream_rsd(STREAMFILE *sf) {
#ifdef VGM_USE_FFMPEG
case 0x574D4120: { /* "WMA " [Scarface (Xbox)] */
ffmpeg_codec_data *ffmpeg_data = NULL;
/* mini header + WMA header at start_offset */
ffmpeg_data = init_ffmpeg_offset(sf, start_offset+0x08,data_size);
if (!ffmpeg_data) goto fail;
vgmstream->codec_data = ffmpeg_data;
vgmstream->codec_data = init_ffmpeg_offset(sf, start_offset+0x08,data_size);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
vgmstream->num_samples = (int32_t)ffmpeg_data->totalSamples; /* an estimation, sometimes cuts files a bit early */
//vgmstream->num_samples = read_32bitLE(start_offset + 0x00, sf) / channel_count / 2; /* may be PCM data size, but not exact */
vgmstream->num_samples = ffmpeg_get_samples(vgmstream->codec_data); /* an estimation, sometimes cuts files a bit early */
//vgmstream->num_samples = read_32bitLE(start_offset + 0x00, sf) / channels / 2; /* may be PCM data size, but not exact */
vgmstream->sample_rate = read_32bitLE(start_offset + 0x04, sf);
break;
}
@ -170,7 +168,6 @@ VGMSTREAM * init_vgmstream_rsd(STREAMFILE *sf) {
}
case 0x584D4120: { /* "XMA " [Crash of the Titans (X360)-v1, Crash: Mind over Mutant (X360)-v2] */
ffmpeg_codec_data *ffmpeg_data = NULL;
uint8_t buf[0x100];
size_t bytes, xma_size, block_size, block_count;
int xma_version;
@ -199,15 +196,14 @@ VGMSTREAM * init_vgmstream_rsd(STREAMFILE *sf) {
}
bytes = ffmpeg_make_riff_xma2(buf,sizeof(buf), vgmstream->num_samples, xma_size, vgmstream->channels, vgmstream->sample_rate, block_count, block_size);
ffmpeg_data = init_ffmpeg_header_offset(sf, buf, bytes, start_offset, xma_size);
if (!ffmpeg_data) goto fail;
vgmstream->codec_data = ffmpeg_data;
vgmstream->codec_data = init_ffmpeg_header_offset(sf, buf, bytes, start_offset, xma_size);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
/* for some reason (dev trickery?) .rsd don't set skip in the bitstream, though they should */
//xma_fix_raw_samples(vgmstream, sf, start_offset,xma_size, 0, 0,0);
ffmpeg_set_skip_samples(ffmpeg_data, 512+64);
ffmpeg_set_skip_samples(vgmstream->codec_data, 512+64);
break;
}
#endif

View File

@ -192,7 +192,7 @@ VGMSTREAM* init_vgmstream_rxws_badrip(STREAMFILE* sf) {
(read_32bitBE(0x10,sf) == 0x464F524D)))
goto fail;
loop_flag = (read_32bitLE(0x3C,sf)!=0xFFFFFFFF);
loop_flag = (read_u32le(0x3C,sf)!=0xFFFFFFFF);
channels=2; /* Always stereo files */
/* build the VGMSTREAM */

View File

@ -1,31 +1,33 @@
#include "meta.h"
/* DVI - from Konami KCE Nayoga SAT games (Castlevania Symphony of the Night, Jikkyou Oshaberi Parodius - Forever with Me) */
VGMSTREAM * init_vgmstream_sat_dvi(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
VGMSTREAM* init_vgmstream_sat_dvi(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count;
int loop_flag, channels;
/* check extension (.pcm: original, .dvi: renamed to header id) */
if ( !check_extensions(streamFile,"pcm,dvi") )
/* checks
* .pcm: original
* .dvi: header id (to be removed )*/
if (!check_extensions(sf,"pcm,dvi"))
goto fail;
/* check header */
if (read_32bitBE(0x00,streamFile) != 0x4456492E) /* "DVI." */
if (!is_id32be(0x00,sf, "DVI."))
goto fail;
start_offset = read_32bitBE(0x04,streamFile);
loop_flag = (read_32bitBE(0x0C,streamFile) != 0xFFFFFFFF);
channel_count = 2; /* no mono files seem to exists */
start_offset = read_s32be(0x04,sf);
loop_flag = (read_s32be(0x0C,sf) != -1);
channels = 2; /* no mono files seem to exists */
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = 44100;
vgmstream->num_samples = read_32bitBE(0x08,streamFile);
vgmstream->loop_start_sample = read_32bitBE(0x0C,streamFile);
vgmstream->loop_end_sample = read_32bitBE(0x08,streamFile);
vgmstream->num_samples = read_s32be(0x08,sf);
vgmstream->loop_start_sample = read_s32be(0x0C,sf);
vgmstream->loop_end_sample = read_s32be(0x08,sf);
vgmstream->coding_type = coding_DVI_IMA_int;
vgmstream->layout_type = layout_interleave;
@ -34,12 +36,11 @@ VGMSTREAM * init_vgmstream_sat_dvi(STREAMFILE *streamFile) {
/* at 0x10 (L) / 0x20 (R): probably ADPCM loop history @+0x00 and step @+0x17 (not init values) */
/* open the file for reading */
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
if (!vgmstream_open_stream(vgmstream, sf, start_offset) )
goto fail;
/* for some reason right channel goes first (tested in SOTN vs emu and PS/OST version), swap offsets */
if (channel_count == 2) {
if (channels == 2) {
off_t temp = vgmstream->ch[0].offset;
vgmstream->ch[0].channel_start_offset =
vgmstream->ch[0].offset = vgmstream->ch[1].offset;

View File

@ -1,99 +1,126 @@
#include "meta.h"
#include "../coding/coding.h"
/* SDF - from Beyond Reality games */
VGMSTREAM * init_vgmstream_sdf(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
size_t data_size;
int loop_flag, channel_count, sample_rate, interleave, coefs_offset;
/* checks */
if (!check_extensions(streamFile,"sdf"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x53444600) /* "SDF\0" */
goto fail;
if (read_32bitBE(0x04,streamFile) != 0x03000000) /* version? */
goto fail;
data_size = read_32bitLE(0x08,streamFile);
start_offset = get_streamfile_size(streamFile) - data_size;
switch(start_offset) {
case 0x18: /* Agent Hugo - Lemoon Twist (PS2)*/
sample_rate = read_32bitLE(0x0c,streamFile);
channel_count = read_32bitLE(0x10,streamFile);
interleave = read_32bitLE(0x14,streamFile);
break;
case 0x78: /* Gummy Bears Mini Golf (3DS) */
sample_rate = read_32bitLE(0x10,streamFile);
channel_count = read_32bitLE(0x14,streamFile);
interleave = read_32bitLE(0x18,streamFile);
coefs_offset = 0x1c;
break;
case 0x84: /* Mr. Bean's Wacky World (Wii) */
sample_rate = read_32bitLE(0x10,streamFile);
channel_count = read_32bitLE(0x14,streamFile);
interleave = read_32bitLE(0x18,streamFile);
data_size = read_32bitLE(0x20,streamFile); /* usable size */
coefs_offset = 0x28;
break;
default:
goto fail;
}
loop_flag = 1;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_SDF;
vgmstream->sample_rate = sample_rate;
switch(start_offset) {
case 0x18:
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 0x78:
case 0x84:
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = interleave;
if (vgmstream->interleave_block_size == 0) /* Gummy Bears Mini Golf */
vgmstream->interleave_block_size = data_size / channel_count;
vgmstream->num_samples = dsp_bytes_to_samples(data_size,channel_count);
dsp_read_coefs_le(vgmstream, streamFile, coefs_offset+0x00,0x2e);
dsp_read_hist_le (vgmstream, streamFile, coefs_offset+0x24,0x2e);
break;
default:
goto fail;
}
/* most songs simply repeat; don't loop if too short (in seconds) */
if (vgmstream->num_samples > 10*sample_rate) {
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = vgmstream->num_samples;
}
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
#include "meta.h"
#include "../coding/coding.h"
typedef enum { PSX, PCM, DSP } sdf_codec;
/* SDF - from Beyond Reality games */
VGMSTREAM* init_vgmstream_sdf(STREAMFILE* sf) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
size_t data_size;
int loop_flag, channels, sample_rate, interleave, coefs_offset;
sdf_codec codec;
/* checks */
if (!check_extensions(sf,"sdf"))
goto fail;
if (!is_id32be(0x00,sf, "SDF\0"))
goto fail;
if (read_u32le(0x04,sf) != 3) /* version? */
goto fail;
data_size = read_u32le(0x08,sf);
start_offset = get_streamfile_size(sf) - data_size;
switch(start_offset) {
case 0x18:
if (read_u32le(0x10,sf) > 6) {
/* Hugo Magic in the Troll Woods (NDS) */
/* 0x0c: some size? */
sample_rate = read_s32le(0x10,sf);
channels = read_u8(0x14,sf);
/* 0x14: 1? */
interleave = read_u16le(0x16,sf);
codec = PCM;
}
else {
/* Agent Hugo: Lemoon Twist (PS2) */
sample_rate = read_s32le(0x0c,sf);
channels = read_u32le(0x10,sf);
interleave = read_u32le(0x14,sf);
codec = PSX;
}
break;
case 0x78: /* Gummy Bears Mini Golf (3DS) */
sample_rate = read_s32le(0x10,sf);
channels = read_u32le(0x14,sf);
interleave = read_u32le(0x18,sf);
coefs_offset = 0x1c;
codec = DSP;
break;
case 0x84: /* Mr. Bean's Wacky World (Wii) */
sample_rate = read_s32le(0x10,sf);
channels = read_u32le(0x14,sf);
interleave = read_u32le(0x18,sf);
data_size = read_u32le(0x20,sf); /* usable size */
coefs_offset = 0x28;
codec = DSP;
break;
default:
goto fail;
}
loop_flag = 1;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_SDF;
vgmstream->sample_rate = sample_rate;
switch(codec) {
case PCM:
vgmstream->coding_type = coding_PCM16LE;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = interleave;
vgmstream->num_samples = pcm16_bytes_to_samples(data_size, channels);
break;
case 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, channels);
break;
case DSP:
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = interleave;
if (vgmstream->interleave_block_size == 0) /* Gummy Bears Mini Golf */
vgmstream->interleave_block_size = data_size / channels;
vgmstream->num_samples = dsp_bytes_to_samples(data_size, channels);
dsp_read_coefs_le(vgmstream, sf, coefs_offset+0x00,0x2e);
dsp_read_hist_le (vgmstream, sf, coefs_offset+0x24,0x2e);
break;
default:
goto fail;
}
/* most songs simply repeat; don't loop if too short (in seconds) */
if (vgmstream->num_samples > 10*sample_rate) {
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = vgmstream->num_samples;
}
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -192,7 +192,7 @@ VGMSTREAM* init_vgmstream_sqex_scd(STREAMFILE* sf) {
}
/* actual Ogg init */
ogg_vgmstream = init_vgmstream_ogg_vorbis_callbacks(sf, NULL, start_offset, &ovmi);
ogg_vgmstream = init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi);
if (ogg_vgmstream && name_offset)
read_string(ogg_vgmstream->stream_name, PATH_LIMIT, name_offset, sf);
return ogg_vgmstream;

View File

@ -172,7 +172,7 @@ VGMSTREAM* init_vgmstream_sqex_sead(STREAMFILE* sf) {
/* 0x18: reserved x2 */
/* 0x20: seek table */
ogg_vgmstream = init_vgmstream_ogg_vorbis_callbacks(sf, NULL, subfile_offset, &ovmi);
ogg_vgmstream = init_vgmstream_ogg_vorbis_config(sf, subfile_offset, &ovmi);
if (ogg_vgmstream) {
ogg_vgmstream->num_streams = vgmstream->num_streams;
ogg_vgmstream->stream_size = vgmstream->stream_size;

View File

@ -150,8 +150,8 @@ VGMSTREAM* init_vgmstream_str_wav(STREAMFILE* sf) {
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
vgmstream->num_samples = ffmpeg_data->totalSamples;
if (vgmstream->channels != ffmpeg_data->channels)
vgmstream->num_samples = ffmpeg_get_samples(ffmpeg_data);
if (vgmstream->channels != ffmpeg_get_channels(ffmpeg_data))
goto fail;
break;

View File

@ -4,9 +4,9 @@
/* .STRM - from Abylight 3DS games [Cursed Castilla (3DS)] */
VGMSTREAM* init_vgmstream_strm_abylight(STREAMFILE* sf) {
VGMSTREAM * vgmstream = NULL;
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count, sample_rate;
int loop_flag, channel_count, sample_rate, skip_samples;
size_t data_size;
@ -22,6 +22,7 @@ VGMSTREAM* init_vgmstream_strm_abylight(STREAMFILE* sf) {
loop_flag = 0;
channel_count = 2; /* there are various possible fields but all files are stereo */
sample_rate = read_32bitLE(0x08,sf);
skip_samples = 1024; /* assumed, maybe a bit more */
start_offset = 0x1e;
data_size = read_32bitLE(0x10,sf);
@ -42,14 +43,12 @@ VGMSTREAM* init_vgmstream_strm_abylight(STREAMFILE* sf) {
#ifdef VGM_USE_FFMPEG
{
vgmstream->codec_data = init_ffmpeg_aac(sf, start_offset, data_size);
vgmstream->codec_data = init_ffmpeg_aac(sf, start_offset, data_size, skip_samples);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
/* assumed, maybe a bit more */
ffmpeg_set_skip_samples(vgmstream->codec_data, 1024);
vgmstream->num_samples -= 1024;
vgmstream->num_samples -= skip_samples;
}
#else
goto fail;

View File

@ -483,10 +483,10 @@ VGMSTREAM* init_vgmstream_txth(STREAMFILE* sf) {
if (!ffmpeg_data) goto fail;
if (vgmstream->num_samples == 0)
vgmstream->num_samples = ffmpeg_data->totalSamples; /* sometimes works */
vgmstream->num_samples = ffmpeg_get_samples(ffmpeg_data); /* sometimes works */
}
else if (txth.codec == AAC) {
ffmpeg_data = init_ffmpeg_aac(txth.sf_body, txth.start_offset, txth.data_size);
ffmpeg_data = init_ffmpeg_aac(txth.sf_body, txth.start_offset, txth.data_size, 0);
if (!ffmpeg_data) goto fail;
}
else {
@ -1553,7 +1553,7 @@ static int read_name_table_keyval(txth_header* txth, const char* line, char* key
//todo names with # and subsongs don't work
/* ignore comments (that aren't subsongs) */
if (line[0] == '#' && strchr(line,':') < 0)
if (line[0] == '#' && strchr(line,':') == NULL)
return 0;
/* try "(name): (val))" */

View File

@ -599,7 +599,7 @@ fail:
}
static VGMSTREAM* init_vgmstream_ubi_bao_silence(ubi_bao_header* bao, STREAMFILE* sf) {
static VGMSTREAM* init_vgmstream_ubi_bao_silence(ubi_bao_header* bao) {
VGMSTREAM* vgmstream = NULL;
int channels, sample_rate;
int32_t num_samples;
@ -660,7 +660,7 @@ static VGMSTREAM* init_vgmstream_ubi_bao_header(ubi_bao_header* bao, STREAMFILE*
break;
case UBI_SILENCE:
vgmstream = init_vgmstream_ubi_bao_silence(bao, sf);
vgmstream = init_vgmstream_ubi_bao_silence(bao);
break;
default:
@ -990,7 +990,7 @@ fail:
}
/* adjust some common values */
static int parse_values(ubi_bao_header* bao, STREAMFILE* sf) {
static int parse_values(ubi_bao_header* bao) {
if (bao->type == UBI_SEQUENCE || bao->type == UBI_SILENCE)
return 1;
@ -1228,7 +1228,7 @@ static int parse_header(ubi_bao_header* bao, STREAMFILE* sf, off_t offset) {
goto fail;
}
if (!parse_values(bao, sf))
if (!parse_values(bao))
goto fail;
if (!parse_offsets(bao, sf))

View File

@ -1,380 +1,385 @@
#include "meta.h"
#include "../coding/coding.h"
static int get_loop_points(STREAMFILE *streamFile, int *out_loop_start, int *out_loop_end);
/* Jade RIFF - from Ubisoft Jade engine games [Beyond Good & Evil (multi), Rayman Raving Rabbids 1/2 (multi)] */
VGMSTREAM * init_vgmstream_ubi_jade(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset, first_offset = 0xc;
off_t fmt_offset, data_offset;
size_t fmt_size, data_size;
int loop_flag, channel_count, sample_rate, codec, block_size;
int loop_start = 0, loop_end = 0;
int is_jade_v2 = 0;
/* checks */
/* .waa: ambiances, .wam: music, .wac: sfx, .wad: dialogs (usually)
* .wav: Beyond Good & Evil HD (PS3), .psw: fake/badly extracted names [ex. Rayman Raving Rabbids (PS2)] */
if (!check_extensions(streamFile,"waa,wac,wad,wam,wav,lwav,psw"))
goto fail;
/* a slightly twisted RIFF with custom codecs */
if (read_32bitBE(0x00,streamFile) != 0x52494646 || /* "RIFF" */
read_32bitBE(0x08,streamFile) != 0x57415645) /* "WAVE" */
goto fail;
if (check_extensions(streamFile,"psw")) { /* .psw are incorrectly extracted missing 0x04 at the end */
if (read_32bitLE(0x04,streamFile)+0x04 != get_streamfile_size(streamFile))
goto fail;
}
else {
if (read_32bitLE(0x04,streamFile)+0x04+0x04 != get_streamfile_size(streamFile))
goto fail;
}
if (!find_chunk(streamFile, 0x666d7420,first_offset,0, &fmt_offset,&fmt_size, 0, 0)) /* "fmt " */
goto fail;
if (!find_chunk(streamFile, 0x64617461,first_offset,0, &data_offset,&data_size, 0, 0)) /* "data" */
goto fail;
/* ignore LyN RIFF (needed as codec 0xFFFE is reused) */
{
off_t fact_offset;
size_t fact_size;
if (find_chunk(streamFile, 0x66616374,first_offset,0, &fact_offset,&fact_size, 0, 0)) { /* "fact" */
if (fact_size == 0x10 && read_32bitBE(fact_offset+0x04, streamFile) == 0x4C794E20) /* "LyN " */
goto fail; /* parsed elsewhere */
/* Jade doesn't use "fact", though */
}
}
/* parse format */
{
if (fmt_size < 0x10)
goto fail;
codec = (uint16_t)read_16bitLE(fmt_offset+0x00,streamFile);
channel_count = read_16bitLE(fmt_offset+0x02,streamFile);
sample_rate = read_32bitLE(fmt_offset+0x04,streamFile);
block_size = (uint16_t)read_16bitLE(fmt_offset+0x0c,streamFile);
/* 0x08: average bytes, 0x0e: bps, etc */
/* autodetect Jade "v2", uses a different interleave [Rayman Raving Rabbids (PS2/Wii)] */
switch(codec) {
case 0xFFFF: { /* PS2 */
int i;
/* half interleave check as there is no flag (ends with the PS-ADPCM stop frame) */
for (i = 0; i < channel_count; i++) {
off_t end_frame = data_offset + (data_size / channel_count) * (i+1) - 0x10;
if (read_32bitBE(end_frame+0x00,streamFile) != 0x07007777 ||
read_32bitBE(end_frame+0x04,streamFile) != 0x77777777 ||
read_32bitBE(end_frame+0x08,streamFile) != 0x77777777 ||
read_32bitBE(end_frame+0x0c,streamFile) != 0x77777777) {
is_jade_v2 = 1;
break;
}
}
break;
}
case 0xFFFE: /* GC/Wii */
is_jade_v2 = (read_16bitLE(fmt_offset+0x10,streamFile) == 0); /* extra data size (0x2e*channels) */
break;
}
/* hopefully catches PC Rabbids */
if (find_chunk(streamFile, 0x63756520,first_offset,0, NULL,NULL, 0, 0)) { /* "cue " */
is_jade_v2 = 1;
}
}
/* get loop points */
if (is_jade_v2) {
loop_flag = get_loop_points(streamFile, &loop_start, &loop_end); /* loops in "LIST" */
}
else {
/* BG&E files don't contain looping information, so the looping is done by extension.
* wam and waa contain ambient sounds and music, so often they contain looped music.
* Later, if the file is too short looping will be disabled. */
loop_flag = check_extensions(streamFile,"waa,wam");
}
start_offset = data_offset;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = sample_rate;
vgmstream->meta_type = meta_UBI_JADE;
if (is_jade_v2) {
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = loop_end;
}
switch(codec) {
case 0x0069: /* Xbox */
/* Peter Jackson's King Kong uses 0x14 (other versions don't) */
if (fmt_size != 0x12 && fmt_size != 0x14) goto fail;
if (block_size != 0x24*channel_count) goto fail;
vgmstream->coding_type = coding_XBOX_IMA;
vgmstream->layout_type = layout_none;
vgmstream->num_samples = xbox_ima_bytes_to_samples(data_size, channel_count);
if (!is_jade_v2) {
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = vgmstream->num_samples;
}
break;
case 0xFFFF: /* PS2 */
if (fmt_size != 0x12) goto fail;
if (block_size != 0x10) goto fail;
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_interleave;
if (is_jade_v2) {
vgmstream->interleave_block_size = 0x6400;
if (vgmstream->interleave_block_size)
vgmstream->interleave_last_block_size = (data_size % (vgmstream->interleave_block_size*vgmstream->channels)) / vgmstream->channels;
}
else {
vgmstream->interleave_block_size = data_size / channel_count;
}
vgmstream->num_samples = ps_bytes_to_samples(data_size, channel_count);
if (!is_jade_v2) {
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = vgmstream->num_samples;
}
break;
case 0xFFFE: /* GC/Wii */
if (fmt_size != 0x12) goto fail;
if (block_size != 0x08) goto fail;
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_interleave;
vgmstream->num_samples = dsp_bytes_to_samples(data_size, channel_count);
if (!is_jade_v2) {
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = vgmstream->num_samples;
}
/* coefs / interleave */
if (is_jade_v2) {
vgmstream->interleave_block_size = 0x6400;
if (vgmstream->interleave_block_size)
vgmstream->interleave_last_block_size = ((data_size % (vgmstream->interleave_block_size*vgmstream->channels))/2+7)/8*8;
{
static const int16_t coef[16] = { /* default Ubisoft coefs, from ELF */
0x04ab,0xfced,0x0789,0xfedf,0x09a2,0xfae5,0x0c90,0xfac1,
0x084d,0xfaa4,0x0982,0xfdf7,0x0af6,0xfafa,0x0be6,0xfbf5
};
int i, ch;
for (ch = 0; ch < channel_count; ch++) {
for (i = 0; i < 16; i++) {
vgmstream->ch[ch].adpcm_coef[i] = coef[i];
}
}
}
}
else {
/* has extra 0x2e coefs before each channel, not counted in data_size */
vgmstream->interleave_block_size = (data_size + 0x2e*channel_count) / channel_count;
dsp_read_coefs_be(vgmstream, streamFile, start_offset+0x00, vgmstream->interleave_block_size);
dsp_read_hist_be (vgmstream, streamFile, start_offset+0x20, vgmstream->interleave_block_size);
start_offset += 0x2e;
}
break;
case 0x0002: /* PC */
if (fmt_size != 0x12) goto fail;
if (block_size != 0x24*channel_count) goto fail;
vgmstream->coding_type = coding_MSADPCM;
vgmstream->layout_type = layout_none;
vgmstream->frame_size = block_size;
vgmstream->num_samples = msadpcm_bytes_to_samples(data_size, vgmstream->frame_size, channel_count);
if (!is_jade_v2) {
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = vgmstream->num_samples;
}
break;
case 0x0001: { /* PS3 */
VGMSTREAM *temp_vgmstream = NULL;
STREAMFILE *temp_sf = NULL;
if (fmt_size != 0x10) goto fail;
if (block_size != 0x02*channel_count) goto fail;
/* a MSF (usually ATRAC3) masquerading as PCM */
if (read_32bitBE(start_offset, streamFile) != 0x4D534643) /* "MSF\43" */
goto fail;
temp_sf = setup_subfile_streamfile(streamFile, start_offset, data_size, "msf");
if (!temp_sf) goto fail;
temp_vgmstream = init_vgmstream_msf(temp_sf);
close_streamfile(temp_sf);
if (!temp_vgmstream) goto fail;
temp_vgmstream->meta_type = vgmstream->meta_type;
close_vgmstream(vgmstream);
return temp_vgmstream;
}
default: /* X360 uses .XMA */
goto fail;
}
/* V1 loops by extension, try to detect incorrectly looped jingles (too short) */
if (!is_jade_v2) {
if(loop_flag
&& vgmstream->num_samples < 15*sample_rate) { /* in seconds */
vgmstream->loop_flag = 0;
}
}
if ( !vgmstream_open_stream(vgmstream,streamFile,start_offset) )
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
/* extract loops from "cue /LIST", returns if loops (info from Droolie) */
static int get_loop_points(STREAMFILE *streamFile, int *out_loop_start, int *out_loop_end) {
off_t cue_offset, list_offset;
size_t cue_size, list_size;
off_t offset, first_offset = 0x0c;
int i, cue_count, loop_id = 0, loop_start = 0, loop_end = 0;
/* unlooped files may contain LIST, but also may not */
if (!find_chunk(streamFile, 0x63756520,first_offset,0, &cue_offset,&cue_size, 0, 0)) /* "cue " */
goto fail;
if (!find_chunk(streamFile, 0x4C495354,first_offset,0, &list_offset,&list_size, 0, 0)) /* "LIST" */
goto fail;
offset = list_offset + 0x04;
while (offset < list_offset + list_size) {
uint32_t chunk_id = read_32bitBE(offset+0x00, streamFile);
uint32_t chunk_size = read_32bitLE(offset+0x04, streamFile);
offset += 0x08;
switch(chunk_id) {
case 0x6C61626C: /* "labl" */
if (read_32bitBE(offset+0x04, streamFile) == 0x6C6F6F70) /* "loop", actually an string tho */
loop_id = read_32bitLE(offset+0x00, streamFile);
chunk_size += (chunk_size % 2) ? 1 : 0; /* string is even-padded after size */
break;
case 0x6C747874: /* "ltxt" */
if (loop_id == read_32bitLE(offset+0x00, streamFile))
loop_end = read_32bitLE(offset+0x04, streamFile);
break;
default:
VGM_LOG("Jade: unknown LIST chunk\n");
goto fail;
}
offset += chunk_size;
}
if (!loop_end)
return 0;
cue_count = read_32bitLE(cue_offset+0x00, streamFile);
for (i = 0; i < cue_count; i++) {
if (loop_id == read_32bitLE(cue_offset+0x04 + i*0x18 + 0x00, streamFile)) {
loop_start = read_32bitLE(cue_offset+0x04 + i*0x18 + 0x04, streamFile);
loop_end += loop_start;
break;
}
}
*out_loop_start = loop_start;
*out_loop_end = loop_end;
return 1;
fail:
return 0;
}
/* Jade RIFF in containers */
VGMSTREAM * init_vgmstream_ubi_jade_container(STREAMFILE *streamFile) {
VGMSTREAM *vgmstream = NULL;
STREAMFILE *temp_streamFile = NULL;
off_t subfile_offset;
size_t subfile_size;
/* Jade packs files in bigfiles, and once extracted the sound files have extra engine data before
* the RIFF + padding after. Most extractors don't remove the padding correctly, so here we add support. */
/* checks */
/* standard Jade exts + .xma for padded XMA used in Beyond Good & Evil HD (X360) */
if (!check_extensions(streamFile,"waa,wac,wad,wam,wav,lwav,xma"))
goto fail;
if (read_32bitBE(0x04,streamFile) == 0x52494646 &&
read_32bitLE(0x00,streamFile)+0x04 == get_streamfile_size(streamFile)) {
/* data size + RIFF + padding */
subfile_offset = 0x04;
}
else if (read_32bitBE(0x00,streamFile) == 0x52494646 &&
read_32bitLE(0x04,streamFile)+0x04+0x04 < get_streamfile_size(streamFile) &&
(get_streamfile_size(streamFile) + 0x04) % 0x800 == 0) {
/* RIFF + padding with data size removed (bad extraction) */
subfile_offset = 0x00;
}
else if (read_32bitBE(0x04,streamFile) == 0x52494646 &&
read_32bitLE(0x00,streamFile) == get_streamfile_size(streamFile)) {
/* data_size + RIFF + padding - 0x04 (bad extraction) */
subfile_offset = 0x04;
}
else {
goto fail;
}
subfile_size = read_32bitLE(subfile_offset+0x04,streamFile) + 0x04+0x04;
temp_streamFile = setup_subfile_streamfile(streamFile, subfile_offset,subfile_size, NULL);
if (!temp_streamFile) goto fail;
if (check_extensions(streamFile,"xma")) {
vgmstream = init_vgmstream_xma(temp_streamFile);
} else {
vgmstream = init_vgmstream_ubi_jade(temp_streamFile);
}
close_streamfile(temp_streamFile);
return vgmstream;
fail:
close_streamfile(temp_streamFile);
close_vgmstream(vgmstream);
return NULL;
}
#include "meta.h"
#include "../coding/coding.h"
static int get_loop_points(STREAMFILE* sf, int* p_loop_start, int* p_loop_end);
/* Jade RIFF - from Ubisoft Jade engine games [Beyond Good & Evil (multi), Rayman Raving Rabbids 1/2 (multi)] */
VGMSTREAM* init_vgmstream_ubi_jade(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset, first_offset = 0xc;
off_t fmt_offset, data_offset;
size_t fmt_size, data_size;
int loop_flag, channel_count, sample_rate, codec, block_size;
int loop_start = 0, loop_end = 0;
int is_jade_v2 = 0;
/* checks */
/* .waa: ambiances, .wam: music, .wac: sfx, .wad: dialogs (usually)
* .wav: Beyond Good & Evil HD (PS3)
* .psw: fake/badly extracted names [ex. Rayman Raving Rabbids (PS2)] */
if (!check_extensions(sf,"waa,wac,wad,wam,wav,lwav,psw"))
goto fail;
/* a slightly twisted RIFF with custom codecs */
if (!is_id32be(0x00,sf, "RIFF") ||
!is_id32be(0x08,sf, "WAVE"))
goto fail;
if (check_extensions(sf,"psw")) { /* .psw are incorrectly extracted missing 0x04 at the end */
if (read_32bitLE(0x04,sf)+0x04 != get_streamfile_size(sf))
goto fail;
}
else {
if (read_32bitLE(0x04,sf)+0x04+0x04 != get_streamfile_size(sf))
goto fail;
}
if (!find_chunk(sf, 0x666d7420,first_offset,0, &fmt_offset,&fmt_size, 0, 0)) /* "fmt " */
goto fail;
if (!find_chunk(sf, 0x64617461,first_offset,0, &data_offset,&data_size, 0, 0)) /* "data" */
goto fail;
/* ignore LyN RIFF (needed as codec 0xFFFE is reused) */
{
off_t fact_offset;
size_t fact_size;
if (find_chunk(sf, 0x66616374,first_offset,0, &fact_offset,&fact_size, 0, 0)) { /* "fact" */
if (fact_size == 0x10 && read_32bitBE(fact_offset+0x04, sf) == 0x4C794E20) /* "LyN " */
goto fail; /* parsed elsewhere */
/* Jade doesn't use "fact", though */
}
}
/* parse format */
{
if (fmt_size < 0x10)
goto fail;
codec = (uint16_t)read_16bitLE(fmt_offset+0x00,sf);
channel_count = read_16bitLE(fmt_offset+0x02,sf);
sample_rate = read_32bitLE(fmt_offset+0x04,sf);
block_size = (uint16_t)read_16bitLE(fmt_offset+0x0c,sf);
/* 0x08: average bytes, 0x0e: bps, etc */
/* autodetect Jade "v2", uses a different interleave [Rayman Raving Rabbids (PS2/Wii)] */
switch(codec) {
case 0xFFFF: { /* PS2 */
int i;
/* half interleave check as there is no flag (ends with the PS-ADPCM stop frame) */
for (i = 0; i < channel_count; i++) {
off_t end_frame = data_offset + (data_size / channel_count) * (i+1) - 0x10;
if (read_32bitBE(end_frame+0x00,sf) != 0x07007777 ||
read_32bitBE(end_frame+0x04,sf) != 0x77777777 ||
read_32bitBE(end_frame+0x08,sf) != 0x77777777 ||
read_32bitBE(end_frame+0x0c,sf) != 0x77777777) {
is_jade_v2 = 1;
break;
}
}
break;
}
case 0xFFFE: /* GC/Wii */
is_jade_v2 = (read_16bitLE(fmt_offset+0x10,sf) == 0); /* extra data size (0x2e*channels) */
break;
default:
break;
}
/* hopefully catches PC Rabbids */
if (find_chunk(sf, 0x63756520,first_offset,0, NULL,NULL, 0, 0)) { /* "cue " */
is_jade_v2 = 1;
}
}
/* get loop points */
if (is_jade_v2) {
loop_flag = get_loop_points(sf, &loop_start, &loop_end); /* loops in "LIST" */
}
else {
/* BG&E files don't contain looping information, so the looping is done by extension.
* wam and waa contain ambient sounds and music, so often they contain looped music.
* Later, if the file is too short looping will be disabled. */
loop_flag = check_extensions(sf,"waa,wam");
}
start_offset = data_offset;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = sample_rate;
vgmstream->meta_type = meta_UBI_JADE;
if (is_jade_v2) {
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = loop_end;
}
switch(codec) {
case 0x0069: /* Xbox */
/* Peter Jackson's King Kong uses 0x14 (other versions don't) */
if (fmt_size != 0x12 && fmt_size != 0x14) goto fail;
if (block_size != 0x24*channel_count) goto fail;
vgmstream->coding_type = coding_XBOX_IMA;
vgmstream->layout_type = layout_none;
vgmstream->num_samples = xbox_ima_bytes_to_samples(data_size, channel_count);
if (!is_jade_v2) {
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = vgmstream->num_samples;
}
break;
case 0xFFFF: /* PS2 */
if (fmt_size != 0x12) goto fail;
if (block_size != 0x10) goto fail;
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_interleave;
if (is_jade_v2) {
vgmstream->interleave_block_size = 0x6400;
if (vgmstream->interleave_block_size)
vgmstream->interleave_last_block_size = (data_size % (vgmstream->interleave_block_size*vgmstream->channels)) / vgmstream->channels;
}
else {
vgmstream->interleave_block_size = data_size / channel_count;
}
vgmstream->num_samples = ps_bytes_to_samples(data_size, channel_count);
if (!is_jade_v2) {
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = vgmstream->num_samples;
}
break;
case 0xFFFE: /* GC/Wii */
if (fmt_size != 0x12) goto fail;
if (block_size != 0x08) goto fail;
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_interleave;
vgmstream->num_samples = dsp_bytes_to_samples(data_size, channel_count);
if (!is_jade_v2) {
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = vgmstream->num_samples;
}
/* coefs / interleave */
if (is_jade_v2) {
vgmstream->interleave_block_size = 0x6400;
if (vgmstream->interleave_block_size)
vgmstream->interleave_last_block_size = ((data_size % (vgmstream->interleave_block_size*vgmstream->channels))/2+7)/8*8;
{
static const int16_t coef[16] = { /* default Ubisoft coefs, from ELF */
0x04ab,0xfced,0x0789,0xfedf,0x09a2,0xfae5,0x0c90,0xfac1,
0x084d,0xfaa4,0x0982,0xfdf7,0x0af6,0xfafa,0x0be6,0xfbf5
};
int i, ch;
for (ch = 0; ch < channel_count; ch++) {
for (i = 0; i < 16; i++) {
vgmstream->ch[ch].adpcm_coef[i] = coef[i];
}
}
}
}
else {
/* has extra 0x2e coefs before each channel, not counted in data_size */
vgmstream->interleave_block_size = (data_size + 0x2e*channel_count) / channel_count;
dsp_read_coefs_be(vgmstream, sf, start_offset+0x00, vgmstream->interleave_block_size);
dsp_read_hist_be (vgmstream, sf, start_offset+0x20, vgmstream->interleave_block_size);
start_offset += 0x2e;
}
break;
case 0x0002: /* PC */
if (fmt_size != 0x12) goto fail;
if (block_size != 0x24*channel_count) goto fail;
vgmstream->coding_type = coding_MSADPCM;
vgmstream->layout_type = layout_none;
vgmstream->frame_size = block_size;
vgmstream->num_samples = msadpcm_bytes_to_samples(data_size, vgmstream->frame_size, channel_count);
if (!is_jade_v2) {
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = vgmstream->num_samples;
}
break;
case 0x0001: { /* PS3 */
VGMSTREAM *temp_vgmstream = NULL;
STREAMFILE *temp_sf = NULL;
if (fmt_size != 0x10) goto fail;
if (block_size != 0x02*channel_count) goto fail;
/* a MSF (usually ATRAC3) masquerading as PCM */
if (read_32bitBE(start_offset, sf) != 0x4D534643) /* "MSF\43" */
goto fail;
temp_sf = setup_subfile_streamfile(sf, start_offset, data_size, "msf");
if (!temp_sf) goto fail;
temp_vgmstream = init_vgmstream_msf(temp_sf);
close_streamfile(temp_sf);
if (!temp_vgmstream) goto fail;
temp_vgmstream->meta_type = vgmstream->meta_type;
close_vgmstream(vgmstream);
return temp_vgmstream;
}
default: /* X360 uses .XMA */
goto fail;
}
/* V1 loops by extension, try to detect incorrectly looped jingles (too short) */
if (!is_jade_v2) {
if(loop_flag
&& vgmstream->num_samples < 15*sample_rate) { /* in seconds */
vgmstream->loop_flag = 0;
}
}
if (!vgmstream_open_stream(vgmstream, sf,start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
/* extract loops from "cue /LIST", returns if loops (info from Droolie) */
static int get_loop_points(STREAMFILE *sf, int *out_loop_start, int *out_loop_end) {
off_t cue_offset, list_offset;
size_t cue_size, list_size;
off_t offset, first_offset = 0x0c;
int i, cue_count, loop_id = 0, loop_start = 0, loop_end = 0;
/* unlooped files may contain LIST, but also may not */
if (!find_chunk(sf, 0x63756520,first_offset,0, &cue_offset,&cue_size, 0, 0)) /* "cue " */
goto fail;
if (!find_chunk(sf, 0x4C495354,first_offset,0, &list_offset,&list_size, 0, 0)) /* "LIST" */
goto fail;
offset = list_offset + 0x04;
while (offset < list_offset + list_size) {
uint32_t chunk_id = read_32bitBE(offset+0x00, sf);
uint32_t chunk_size = read_32bitLE(offset+0x04, sf);
offset += 0x08;
switch(chunk_id) {
case 0x6C61626C: /* "labl" */
if (read_32bitBE(offset+0x04, sf) == 0x6C6F6F70) /* "loop", actually an string tho */
loop_id = read_32bitLE(offset+0x00, sf);
chunk_size += (chunk_size % 2) ? 1 : 0; /* string is even-padded after size */
break;
case 0x6C747874: /* "ltxt" */
if (loop_id == read_32bitLE(offset+0x00, sf))
loop_end = read_32bitLE(offset+0x04, sf);
break;
default:
VGM_LOG("Jade: unknown LIST chunk\n");
goto fail;
}
offset += chunk_size;
}
if (!loop_end)
return 0;
cue_count = read_32bitLE(cue_offset+0x00, sf);
for (i = 0; i < cue_count; i++) {
if (loop_id == read_32bitLE(cue_offset+0x04 + i*0x18 + 0x00, sf)) {
loop_start = read_32bitLE(cue_offset+0x04 + i*0x18 + 0x04, sf);
loop_end += loop_start;
break;
}
}
*out_loop_start = loop_start;
*out_loop_end = loop_end;
return 1;
fail:
return 0;
}
/* Jade RIFF in containers */
VGMSTREAM* init_vgmstream_ubi_jade_container(STREAMFILE* sf) {
VGMSTREAM *vgmstream = NULL;
STREAMFILE *temp_sf = NULL;
off_t subfile_offset;
size_t subfile_size;
/* Jade packs files in bigfiles, and once extracted the sound files have extra engine data before
* the RIFF + padding after. Most extractors don't remove the padding correctly, so here we add support. */
/* checks */
/* standard Jade exts + .xma for padded XMA used in Beyond Good & Evil HD (X360) */
if (!check_extensions(sf,"waa,wac,wad,wam,wav,lwav,xma"))
goto fail;
if (read_32bitBE(0x04,sf) == 0x52494646 &&
read_32bitLE(0x00,sf)+0x04 == get_streamfile_size(sf)) {
/* data size + RIFF + padding */
subfile_offset = 0x04;
}
else if (read_32bitBE(0x00,sf) == 0x52494646 &&
read_32bitLE(0x04,sf)+0x04+0x04 < get_streamfile_size(sf) &&
(get_streamfile_size(sf) + 0x04) % 0x800 == 0) {
/* RIFF + padding with data size removed (bad extraction) */
subfile_offset = 0x00;
}
else if (read_32bitBE(0x04,sf) == 0x52494646 &&
read_32bitLE(0x00,sf) == get_streamfile_size(sf)) {
/* data_size + RIFF + padding - 0x04 (bad extraction) */
subfile_offset = 0x04;
}
else {
goto fail;
}
subfile_size = read_32bitLE(subfile_offset+0x04,sf) + 0x04+0x04;
temp_sf = setup_subfile_streamfile(sf, subfile_offset,subfile_size, NULL);
if (!temp_sf) goto fail;
if (check_extensions(sf,"xma")) {
vgmstream = init_vgmstream_xma(temp_sf);
} else {
vgmstream = init_vgmstream_ubi_jade(temp_sf);
}
close_streamfile(temp_sf);
return vgmstream;
fail:
close_streamfile(temp_sf);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -207,7 +207,7 @@ static int parse_dat_header(ubi_sb_header *sb, STREAMFILE *sf);
static int parse_header(ubi_sb_header* sb, STREAMFILE* sf, off_t offset, int index);
static int parse_sb(ubi_sb_header* sb, STREAMFILE* sf, int target_subsong);
static VGMSTREAM* init_vgmstream_ubi_sb_header(ubi_sb_header* sb, STREAMFILE* sf_index, STREAMFILE* sf);
static VGMSTREAM *init_vgmstream_ubi_sb_silence(ubi_sb_header *sb, STREAMFILE *sf_index, STREAMFILE *sf);
static VGMSTREAM *init_vgmstream_ubi_sb_silence(ubi_sb_header *sb);
static int config_sb_platform(ubi_sb_header* sb, STREAMFILE* sf);
static int config_sb_version(ubi_sb_header* sb, STREAMFILE* sf);
@ -542,7 +542,7 @@ static int parse_ubi_bank_header(ubi_sb_header *sb, ubi_sb_header *sb_other, STR
return 0;
}
static void get_ubi_bank_name(ubi_sb_header *sb, STREAMFILE *sf, int bank_number, char *bank_name) {
static void get_ubi_bank_name(ubi_sb_header *sb, int bank_number, char *bank_name) {
if (sb->is_bnm) {
sprintf(bank_name, "Bnk_%d.bnm", bank_number);
} else if (sb->is_dat) {
@ -559,7 +559,7 @@ static int is_other_bank(ubi_sb_header *sb, STREAMFILE *sf, int bank_number) {
char bank_name[255];
get_streamfile_filename(sf, current_name, PATH_LIMIT);
get_ubi_bank_name(sb, sf, bank_number, bank_name);
get_ubi_bank_name(sb, bank_number, bank_name);
return strcmp(current_name, bank_name) != 0;
}
@ -647,7 +647,7 @@ static VGMSTREAM *init_vgmstream_ubi_dat_main(ubi_sb_header *sb, STREAMFILE *sf_
VGM_LOG("UBI DAT: external stream '%s' not found\n", sb->resource_name);
strncat(sb->readable_name, " (missing)", sizeof(sb->readable_name));
sb->duration = (float)pcm_bytes_to_samples(sb->stream_size, sb->channels, 16) / (float)sb->sample_rate;
return init_vgmstream_ubi_sb_silence(sb, sf_index, sf);
return init_vgmstream_ubi_sb_silence(sb);
}
}
@ -1438,7 +1438,7 @@ static VGMSTREAM* init_vgmstream_ubi_sb_sequence(ubi_sb_header* sb, STREAMFILE*
if (sf_bank != sf_index)
close_streamfile(sf_bank);
get_ubi_bank_name(sb, sf, sb->sequence_banks[i], bank_name);
get_ubi_bank_name(sb, sb->sequence_banks[i], bank_name);
sf_bank = open_streamfile_by_filename(sf, bank_name);
/* may be worth trying in localized folder? */
@ -1529,7 +1529,7 @@ fail:
}
static VGMSTREAM* init_vgmstream_ubi_sb_silence(ubi_sb_header* sb, STREAMFILE* sf_index, STREAMFILE* sf) {
static VGMSTREAM* init_vgmstream_ubi_sb_silence(ubi_sb_header* sb) {
VGMSTREAM* vgmstream = NULL;
int channels, sample_rate;
int32_t num_samples;
@ -1585,7 +1585,7 @@ static VGMSTREAM* init_vgmstream_ubi_sb_header(ubi_sb_header* sb, STREAMFILE* sf
break;
case UBI_SILENCE:
vgmstream = init_vgmstream_ubi_sb_silence(sb, sf_index, sf);
vgmstream = init_vgmstream_ubi_sb_silence(sb);
break;
case UBI_NONE:

View File

@ -1,52 +1,52 @@
#include "meta.h"
#include "../layout/layout.h"
#include "../coding/coding.h"
/* .VS - from Melbourne House games [Men in Black II (PS2), Grand Prix Challenge (PS2) */
VGMSTREAM * init_vgmstream_vs(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count;
/* checks */
if (!check_extensions(streamFile, "vs"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0xC8000000)
goto fail;
loop_flag = 0;
channel_count = 2;
start_offset = 0x08;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_VS;
vgmstream->sample_rate = read_32bitLE(0x04,streamFile);
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_blocked_vs;
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
/* calc num_samples */
{
vgmstream->next_block_offset = start_offset;
do {
block_update(vgmstream->next_block_offset,vgmstream);
vgmstream->num_samples += ps_bytes_to_samples(vgmstream->current_block_size, 1);
}
while (vgmstream->next_block_offset < get_streamfile_size(streamFile));
block_update(start_offset, vgmstream);
}
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
#include "meta.h"
#include "../layout/layout.h"
#include "../coding/coding.h"
/* .VS - from Melbourne House games [Men in Black II (PS2), Grand Prix Challenge (PS2) */
VGMSTREAM* init_vgmstream_vs(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
int loop_flag, channels;
/* checks */
if (!check_extensions(sf, "vs"))
goto fail;
if (read_u32be(0x00,sf) != 0xC8000000)
goto fail;
loop_flag = 0;
channels = 2;
start_offset = 0x08;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels,loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_VS;
vgmstream->sample_rate = read_s32le(0x04,sf);
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_blocked_vs;
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
/* calc num_samples */
{
vgmstream->next_block_offset = start_offset;
do {
block_update(vgmstream->next_block_offset,vgmstream);
vgmstream->num_samples += ps_bytes_to_samples(vgmstream->current_block_size, 1);
}
while (vgmstream->next_block_offset < get_streamfile_size(sf));
block_update(start_offset, vgmstream);
}
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -1,56 +1,56 @@
#include "meta.h"
#include "../layout/layout.h"
#include "../coding/coding.h"
/* .vs/STRx - from The Bouncer (PS2) */
VGMSTREAM * init_vgmstream_vs_str(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
int channel_count, loop_flag;
off_t start_offset;
/* checks */
/* .vs: real extension (from .nam container)
* .str: fake, partial header id */
if (!check_extensions(streamFile, "vs,str"))
goto fail;
if (!(read_32bitBE(0x000,streamFile) == 0x5354524C && /* "STRL" */
read_32bitBE(0x800,streamFile) == 0x53545252) && /* "STRR" */
read_32bitBE(0x00,streamFile) != 0x5354524D) /* "STRM" */
goto fail;
loop_flag = 0;
channel_count = (read_32bitBE(0x00,streamFile) == 0x5354524D) ? 1 : 2; /* "STRM"=mono (voices) */
start_offset = 0x00;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_VS_STR;
vgmstream->sample_rate = 44100;
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_blocked_vs_str;
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
/* calc num_samples */
{
vgmstream->next_block_offset = start_offset;
do {
block_update(vgmstream->next_block_offset,vgmstream);
vgmstream->num_samples += ps_bytes_to_samples(vgmstream->current_block_size, 1);
}
while (vgmstream->next_block_offset < get_streamfile_size(streamFile));
block_update(start_offset, vgmstream);
}
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
#include "meta.h"
#include "../layout/layout.h"
#include "../coding/coding.h"
/* .vs/STRx - from The Bouncer (PS2) */
VGMSTREAM* init_vgmstream_vs_str(STREAMFILE* sf) {
VGMSTREAM * vgmstream = NULL;
int channel_count, loop_flag;
off_t start_offset;
/* checks */
/* .vs: real extension (from .nam container)
* .str: fake, partial header id */
if (!check_extensions(sf, "vs,str"))
goto fail;
if (!(read_32bitBE(0x000,sf) == 0x5354524C && /* "STRL" */
read_32bitBE(0x800,sf) == 0x53545252) && /* "STRR" */
read_32bitBE(0x00,sf) != 0x5354524D) /* "STRM" */
goto fail;
loop_flag = 0;
channel_count = (read_32bitBE(0x00,sf) == 0x5354524D) ? 1 : 2; /* "STRM"=mono (voices) */
start_offset = 0x00;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_VS_STR;
vgmstream->sample_rate = 44100;
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_blocked_vs_str;
if (!vgmstream_open_stream(vgmstream,sf,start_offset))
goto fail;
/* calc num_samples */
{
vgmstream->next_block_offset = start_offset;
do {
block_update(vgmstream->next_block_offset,vgmstream);
vgmstream->num_samples += ps_bytes_to_samples(vgmstream->current_block_size, 1);
}
while (vgmstream->next_block_offset < get_streamfile_size(sf));
block_update(start_offset, vgmstream);
}
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -2,42 +2,43 @@
#include "../coding/coding.h"
/* WAF - KID's earlier PC games [ever17 (PC)] (for RLE-compressed WAFs see https://github.com/dsp2003/e17p) */
VGMSTREAM * init_vgmstream_waf(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
VGMSTREAM* init_vgmstream_waf(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count;
int loop_flag, channels;
/* checks */
if (!check_extensions(streamFile, "waf"))
if (!check_extensions(sf, "waf"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x57414600) /* "WAF\0" */
if (!is_id32be(0x00,sf, "WAF\0"))
goto fail;
if (read_32bitLE(0x34,streamFile) + 0x38 != get_streamfile_size(streamFile))
if (read_u32le(0x34,sf) + 0x38 != get_streamfile_size(sf))
goto fail;
channel_count = read_16bitLE(0x06,streamFile);
loop_flag = 0;
channels = read_u16le(0x06,sf);
loop_flag = 0;
start_offset = 0x38;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_WAF;
vgmstream->sample_rate = read_32bitLE(0x08, streamFile);
vgmstream->sample_rate = read_s32le(0x08, sf);
vgmstream->coding_type = coding_MSADPCM;
vgmstream->layout_type = layout_none;
vgmstream->frame_size = read_16bitLE(0x10, streamFile);
vgmstream->frame_size = read_u16le(0x10, sf);
/* 0x04: null?, 0x0c: avg br, 0x12: bps, 0x14: s_p_f, 0x16~34: coefs (a modified RIFF fmt) */
if (!msadpcm_check_coefs(streamFile, 0x16))
if (!msadpcm_check_coefs(sf, 0x16))
goto fail;
vgmstream->num_samples = msadpcm_bytes_to_samples(read_32bitLE(0x34,streamFile), vgmstream->frame_size, channel_count);
vgmstream->num_samples = msadpcm_bytes_to_samples(read_u32le(0x34,sf), vgmstream->frame_size, channels);
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;

View File

@ -1,220 +1,220 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../layout/layout.h"
#define MAX_SEGMENTS 4
/* .WAVE - "EngineBlack" games, segmented [Shantae and the Pirate's Curse (PC/3DS), TMNT: Danger of the Ooze (PS3/3DS)] */
VGMSTREAM * init_vgmstream_wave_segmented(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t segments_offset;
int loop_flag = 0, channel_count, sample_rate;
int32_t num_samples, loop_start_sample = 0, loop_end_sample = 0;
segmented_layout_data *data = NULL;
int segment_count, loop_start_segment = 0, loop_end_segment = 0;
int big_endian;
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
/* checks */
if (!check_extensions(streamFile, "wave"))
goto fail;
if (read_32bitLE(0x00,streamFile) != 0x4DF72D4A && /* header id */
read_32bitBE(0x00,streamFile) != 0x4DF72D4A)
goto fail;
if (read_8bit(0x04,streamFile) != 0x01) /* version? */
goto fail;
/* PS3/X360 games */
big_endian = read_32bitBE(0x00,streamFile) == 0x4DF72D4A;
if (big_endian) {
read_32bit = read_32bitBE;
read_16bit = read_16bitBE;
} else {
read_32bit = read_32bitLE;
read_16bit = read_16bitLE;
}
channel_count = read_8bit(0x05,streamFile);
segment_count = read_16bit(0x06,streamFile);
if (segment_count > MAX_SEGMENTS || segment_count <= 0) goto fail;
loop_start_segment = read_16bit(0x08, streamFile);
loop_end_segment = read_16bit(0x0a, streamFile);
segments_offset = read_32bit(0x0c, streamFile);
sample_rate = read_32bit(0x10, streamFile);
num_samples = read_32bit(0x14, streamFile);
/* 0x18: unknown (usually 0, maybe some count) */
/* init layout */
data = init_layout_segmented(segment_count);
if (!data) goto fail;
/* parse segments (usually: preload + intro + loop + ending, intro/ending may be skipped)
* Often first segment is ADPCM and rest Ogg; may only have one segment. */
{
off_t extradata_offset, table_offset, segment_offset;
size_t segment_size;
int32_t segment_samples;
int codec;
int i, ch;
/* open each segment subfile */
for (i = 0; i < segment_count; i++) {
codec = read_8bit(segments_offset+0x10*i+0x00, streamFile);
/* 0x01(1): unknown (flag? usually 0x00/0x01/0x02) */
if (read_8bit(segments_offset+0x10*i+0x02, streamFile) != 0x01) goto fail; /* unknown */
if (read_8bit(segments_offset+0x10*i+0x03, streamFile) != 0x00) goto fail; /* unknown */
segment_samples = read_32bit(segments_offset+0x10*i+0x04, streamFile);
extradata_offset = read_32bit(segments_offset+0x10*i+0x08, streamFile);
table_offset = read_32bit(segments_offset+0x10*i+0x0c, streamFile);
/* create a sub-VGMSTREAM per segment
* (we'll reopen this streamFile as needed, so each sub-VGMSTREAM is fully independent) */
switch(codec) {
case 0x02: { /* "adpcm" */
data->segments[i] = allocate_vgmstream(channel_count, 0);
if (!data->segments[i]) goto fail;
data->segments[i]->sample_rate = sample_rate;
data->segments[i]->meta_type = meta_WAVE;
data->segments[i]->coding_type = coding_IMA_int;
data->segments[i]->layout_type = layout_none;
data->segments[i]->num_samples = segment_samples;
if (!vgmstream_open_stream(data->segments[i],streamFile,0x00))
goto fail;
/* bizarrely enough channel data isn't sequential (segment0 ch1+ may go after all other segments) */
for (ch = 0; ch < channel_count; ch++) {
segment_offset = read_32bit(table_offset + 0x04*ch, streamFile);
data->segments[i]->ch[ch].channel_start_offset =
data->segments[i]->ch[ch].offset = segment_offset;
/* ADPCM setup */
data->segments[i]->ch[ch].adpcm_history1_32 = read_16bit(extradata_offset+0x04*ch+0x00, streamFile);
data->segments[i]->ch[ch].adpcm_step_index = read_8bit(extradata_offset+0x04*ch+0x02, streamFile);
/* 0x03: reserved */
}
break;
}
case 0x03: { /* "dsp-adpcm" */
data->segments[i] = allocate_vgmstream(channel_count, 0);
if (!data->segments[i]) goto fail;
data->segments[i]->sample_rate = sample_rate;
data->segments[i]->meta_type = meta_WAVE;
data->segments[i]->coding_type = coding_NGC_DSP;
data->segments[i]->layout_type = layout_none;
data->segments[i]->num_samples = segment_samples;
if (!vgmstream_open_stream(data->segments[i],streamFile,0x00))
goto fail;
/* bizarrely enough channel data isn't sequential (segment0 ch1+ may go after all other segments) */
for (ch = 0; ch < channel_count; ch++) {
segment_offset = read_32bit(table_offset + 0x04*ch, streamFile);
data->segments[i]->ch[ch].channel_start_offset =
data->segments[i]->ch[ch].offset = segment_offset;
}
/* ADPCM setup: 0x06 initial ps/hist1/hist2 (per channel) + 0x20 coefs (per channel) */
dsp_read_hist(data->segments[i], streamFile, extradata_offset+0x02, 0x06, big_endian);
dsp_read_coefs(data->segments[i], streamFile, extradata_offset+0x06*channel_count+0x00, 0x20, big_endian);
break;
}
#ifdef VGM_USE_VORBIS
case 0x04: { /* "vorbis" */
ogg_vorbis_meta_info_t ovmi = {0};
segment_offset = read_32bit(table_offset, streamFile);
segment_size = read_32bitBE(segment_offset, streamFile); /* always BE */
ovmi.meta_type = meta_WAVE;
ovmi.stream_size = segment_size;
data->segments[i] = init_vgmstream_ogg_vorbis_callbacks(streamFile, NULL, segment_offset+0x04, &ovmi);
if (!data->segments[i]) goto fail;
if (data->segments[i]->num_samples != segment_samples) {
VGM_LOG("WAVE: segment %i samples != num_samples\n", i);
goto fail;
}
break;
}
#endif
default: /* others: s16be/s16le/mp3 as referenced in the exe? */
VGM_LOG("WAVE: unknown codec\n");
goto fail;
}
}
}
/* setup segmented VGMSTREAMs */
if (!setup_layout_segmented(data))
goto fail;
/* parse samples */
{
int32_t sample_count = 0;
int i;
loop_flag = (loop_start_segment > 0);
for (i = 0; i < segment_count; i++) {
if (loop_flag && loop_start_segment == i) {
loop_start_sample = sample_count;
}
sample_count += data->segments[i]->num_samples;
if (loop_flag && loop_end_segment-1 == i) {
loop_end_sample = sample_count;
}
}
if (sample_count != num_samples) {
VGM_LOG("WAVE: total segments samples %i != num_samples %i\n", sample_count, num_samples);
goto fail;
}
}
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = num_samples;
vgmstream->loop_start_sample = loop_start_sample;
vgmstream->loop_end_sample = loop_end_sample;
vgmstream->meta_type = meta_WAVE_segmented;
vgmstream->stream_size = get_streamfile_size(streamFile); /* wrong kbps otherwise */
/* .wave can mix codecs, usually first segment is a small ADPCM section) */
vgmstream->coding_type = (segment_count == 1 ? data->segments[0]->coding_type : data->segments[1]->coding_type);
vgmstream->layout_type = layout_segmented;
vgmstream->layout_data = data;
return vgmstream;
fail:
free_layout_segmented(data);
close_vgmstream(vgmstream);
return NULL;
}
#include "meta.h"
#include "../coding/coding.h"
#include "../layout/layout.h"
#define MAX_SEGMENTS 4
/* .WAVE - "EngineBlack" games, segmented [Shantae and the Pirate's Curse (PC/3DS), TMNT: Danger of the Ooze (PS3/3DS)] */
VGMSTREAM * init_vgmstream_wave_segmented(STREAMFILE *sf) {
VGMSTREAM * vgmstream = NULL;
off_t segments_offset;
int loop_flag = 0, channel_count, sample_rate;
int32_t num_samples, loop_start_sample = 0, loop_end_sample = 0;
segmented_layout_data *data = NULL;
int segment_count, loop_start_segment = 0, loop_end_segment = 0;
int big_endian;
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
/* checks */
if (!check_extensions(sf, "wave"))
goto fail;
if (read_32bitLE(0x00,sf) != 0x4DF72D4A && /* header id */
read_32bitBE(0x00,sf) != 0x4DF72D4A)
goto fail;
if (read_8bit(0x04,sf) != 0x01) /* version? */
goto fail;
/* PS3/X360 games */
big_endian = read_32bitBE(0x00,sf) == 0x4DF72D4A;
if (big_endian) {
read_32bit = read_32bitBE;
read_16bit = read_16bitBE;
} else {
read_32bit = read_32bitLE;
read_16bit = read_16bitLE;
}
channel_count = read_8bit(0x05,sf);
segment_count = read_16bit(0x06,sf);
if (segment_count > MAX_SEGMENTS || segment_count <= 0) goto fail;
loop_start_segment = read_16bit(0x08, sf);
loop_end_segment = read_16bit(0x0a, sf);
segments_offset = read_32bit(0x0c, sf);
sample_rate = read_32bit(0x10, sf);
num_samples = read_32bit(0x14, sf);
/* 0x18: unknown (usually 0, maybe some count) */
/* init layout */
data = init_layout_segmented(segment_count);
if (!data) goto fail;
/* parse segments (usually: preload + intro + loop + ending, intro/ending may be skipped)
* Often first segment is ADPCM and rest Ogg; may only have one segment. */
{
off_t extradata_offset, table_offset, segment_offset;
size_t segment_size;
int32_t segment_samples;
int codec;
int i, ch;
/* open each segment subfile */
for (i = 0; i < segment_count; i++) {
codec = read_8bit(segments_offset+0x10*i+0x00, sf);
/* 0x01(1): unknown (flag? usually 0x00/0x01/0x02) */
if (read_8bit(segments_offset+0x10*i+0x02, sf) != 0x01) goto fail; /* unknown */
if (read_8bit(segments_offset+0x10*i+0x03, sf) != 0x00) goto fail; /* unknown */
segment_samples = read_32bit(segments_offset+0x10*i+0x04, sf);
extradata_offset = read_32bit(segments_offset+0x10*i+0x08, sf);
table_offset = read_32bit(segments_offset+0x10*i+0x0c, sf);
/* create a sub-VGMSTREAM per segment
* (we'll reopen this sf as needed, so each sub-VGMSTREAM is fully independent) */
switch(codec) {
case 0x02: { /* "adpcm" */
data->segments[i] = allocate_vgmstream(channel_count, 0);
if (!data->segments[i]) goto fail;
data->segments[i]->sample_rate = sample_rate;
data->segments[i]->meta_type = meta_WAVE;
data->segments[i]->coding_type = coding_IMA_int;
data->segments[i]->layout_type = layout_none;
data->segments[i]->num_samples = segment_samples;
if (!vgmstream_open_stream(data->segments[i],sf,0x00))
goto fail;
/* bizarrely enough channel data isn't sequential (segment0 ch1+ may go after all other segments) */
for (ch = 0; ch < channel_count; ch++) {
segment_offset = read_32bit(table_offset + 0x04*ch, sf);
data->segments[i]->ch[ch].channel_start_offset =
data->segments[i]->ch[ch].offset = segment_offset;
/* ADPCM setup */
data->segments[i]->ch[ch].adpcm_history1_32 = read_16bit(extradata_offset+0x04*ch+0x00, sf);
data->segments[i]->ch[ch].adpcm_step_index = read_8bit(extradata_offset+0x04*ch+0x02, sf);
/* 0x03: reserved */
}
break;
}
case 0x03: { /* "dsp-adpcm" */
data->segments[i] = allocate_vgmstream(channel_count, 0);
if (!data->segments[i]) goto fail;
data->segments[i]->sample_rate = sample_rate;
data->segments[i]->meta_type = meta_WAVE;
data->segments[i]->coding_type = coding_NGC_DSP;
data->segments[i]->layout_type = layout_none;
data->segments[i]->num_samples = segment_samples;
if (!vgmstream_open_stream(data->segments[i],sf,0x00))
goto fail;
/* bizarrely enough channel data isn't sequential (segment0 ch1+ may go after all other segments) */
for (ch = 0; ch < channel_count; ch++) {
segment_offset = read_32bit(table_offset + 0x04*ch, sf);
data->segments[i]->ch[ch].channel_start_offset =
data->segments[i]->ch[ch].offset = segment_offset;
}
/* ADPCM setup: 0x06 initial ps/hist1/hist2 (per channel) + 0x20 coefs (per channel) */
dsp_read_hist(data->segments[i], sf, extradata_offset+0x02, 0x06, big_endian);
dsp_read_coefs(data->segments[i], sf, extradata_offset+0x06*channel_count+0x00, 0x20, big_endian);
break;
}
#ifdef VGM_USE_VORBIS
case 0x04: { /* "vorbis" */
ogg_vorbis_meta_info_t ovmi = {0};
segment_offset = read_32bit(table_offset, sf);
segment_size = read_32bitBE(segment_offset, sf); /* always BE */
ovmi.meta_type = meta_WAVE;
ovmi.stream_size = segment_size;
data->segments[i] = init_vgmstream_ogg_vorbis_config(sf, segment_offset+0x04, &ovmi);
if (!data->segments[i]) goto fail;
if (data->segments[i]->num_samples != segment_samples) {
VGM_LOG("WAVE: segment %i samples != num_samples\n", i);
goto fail;
}
break;
}
#endif
default: /* others: s16be/s16le/mp3 as referenced in the exe? */
VGM_LOG("WAVE: unknown codec\n");
goto fail;
}
}
}
/* setup segmented VGMSTREAMs */
if (!setup_layout_segmented(data))
goto fail;
/* parse samples */
{
int32_t sample_count = 0;
int i;
loop_flag = (loop_start_segment > 0);
for (i = 0; i < segment_count; i++) {
if (loop_flag && loop_start_segment == i) {
loop_start_sample = sample_count;
}
sample_count += data->segments[i]->num_samples;
if (loop_flag && loop_end_segment-1 == i) {
loop_end_sample = sample_count;
}
}
if (sample_count != num_samples) {
VGM_LOG("WAVE: total segments samples %i != num_samples %i\n", sample_count, num_samples);
goto fail;
}
}
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = num_samples;
vgmstream->loop_start_sample = loop_start_sample;
vgmstream->loop_end_sample = loop_end_sample;
vgmstream->meta_type = meta_WAVE_segmented;
vgmstream->stream_size = get_streamfile_size(sf); /* wrong kbps otherwise */
/* .wave can mix codecs, usually first segment is a small ADPCM section) */
vgmstream->coding_type = (segment_count == 1 ? data->segments[0]->coding_type : data->segments[1]->coding_type);
vgmstream->layout_type = layout_segmented;
vgmstream->layout_data = data;
return vgmstream;
fail:
free_layout_segmented(data);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -1,138 +1,135 @@
#include "meta.h"
#include "../coding/coding.h"
/* WBAT - Firebrand Games header [Need for Speed: The Run (3DS), Fast & Furious: Showdown (3DS)] */
VGMSTREAM * init_vgmstream_wavebatch(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset, name_offset, offset, stream_offset;
size_t names_size, stream_size;
int loop_flag, channel_count, sample_rate, num_samples;
int big_endian, version, codec;
int total_subsongs, target_subsong = streamFile->stream_index;
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
/* checks */
if (!check_extensions(streamFile, "wavebatch"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x54414257) /* "TABW" */
goto fail;
/* section0: base header */
big_endian = ((uint16_t)read_16bitBE(0x04,streamFile) == 0xFEFF); /* BOM (always LE on 3DS/Android) */
if (big_endian) {
read_32bit = read_32bitBE;
read_16bit = read_16bitBE;
} else {
read_32bit = read_32bitLE;
read_16bit = read_16bitLE;
}
version = read_16bit(0x06, streamFile); /* assumed */
if (version != 0x06 && version != 0x07) /* v6 = NFS: The Run , v7 = F&F Showndown */
goto fail;
total_subsongs = read_32bit(0x08,streamFile);
if (target_subsong == 0) target_subsong = 1;
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
names_size = read_32bit(0x0c,streamFile);
/* 0x10/14: see below */
/* 0x18: data size (all subsongs) */
offset = 0x1c + names_size; /* skip names table */
/* the following 2 sections (rarely) won't match total_subsongs */
/* section1: unknown */
{
size_t unknown_size = read_32bit(0x10,streamFile);
/* 0x00: usually 0, rarely 0x20? */
offset += unknown_size*0x04;
}
/* section2: samples */
{
size_t samples_size = read_32bit(0x14,streamFile);
/* 0x00: num_samples */
offset += samples_size*0x04;
}
/* section3: headers */
{
off_t header_offset = offset+(target_subsong-1)*0x24;
name_offset = read_32bit(header_offset+0x00, streamFile) + 0x1c; /* within name table */
codec = read_32bit(header_offset+0x04, streamFile);
sample_rate = read_32bit(header_offset+0x08, streamFile);
channel_count = read_32bit(header_offset+0x0c, streamFile);
/* 0x10: index within section1/2? */
/* 0x14: flags? 0x01 or (rarely) 0x02 */
stream_offset = read_32bit(header_offset+0x18, streamFile);
stream_size = read_32bit(header_offset+0x1c, streamFile); /* including DSP config */
num_samples = read_32bit(header_offset+0x20, streamFile) / channel_count; /* nibble/PCMs */
offset += total_subsongs*0x24;
}
loop_flag = 0;
start_offset = offset + stream_offset;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = num_samples;
vgmstream->num_streams = total_subsongs;
vgmstream->stream_size = stream_size;
vgmstream->meta_type = meta_WAVEBATCH;
switch(codec) {
case 0x00: /* PCM16 [NASCAR Unleashed (3DS), Solar Flux Pocket (Android)] */
vgmstream->coding_type = big_endian ? coding_PCM16BE : coding_PCM16LE;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x02;
break;
case 0x01: /* PCM8 [Cars 2 (3DS)] */
vgmstream->coding_type = coding_PCM8;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x01;
break;
case 0x02: { /* DSP [WRC FIA World Rally Championship (3DS)] */
size_t config_size = (0x20+0x14)*channel_count + (0x0c)*channel_count; /* coefs+hist + padding */
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = (stream_size - config_size) / channel_count; /* full interleave*/;
dsp_read_coefs(vgmstream,streamFile,start_offset+0x00,0x20+0x14,big_endian);
dsp_read_hist (vgmstream,streamFile,start_offset+0x20,0x14+0x20,big_endian);
start_offset += config_size;
break;
}
default:
VGM_LOG("WAVEBATCH: unknown codec %x\n", codec);
goto fail;
}
read_string(vgmstream->stream_name,STREAM_NAME_SIZE, name_offset,streamFile); /* always null-terminated */
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
#include "meta.h"
#include "../coding/coding.h"
/* WBAT - Firebrand Games header [Need for Speed: The Run (3DS), Fast & Furious: Showdown (3DS)] */
VGMSTREAM * init_vgmstream_wavebatch(STREAMFILE *sf) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset, name_offset, offset, stream_offset;
size_t names_size, stream_size;
int loop_flag, channel_count, sample_rate, num_samples;
int big_endian, version, codec;
int total_subsongs, target_subsong = sf->stream_index;
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
/* checks */
if (!check_extensions(sf, "wavebatch"))
goto fail;
if (!is_id32be(0x00,sf, "TABW"))
goto fail;
/* section0: base header */
big_endian = (read_u16be(0x04,sf) == 0xFEFF); /* BOM (always LE on 3DS/Android) */
if (big_endian) {
read_32bit = read_32bitBE;
read_16bit = read_16bitBE;
} else {
read_32bit = read_32bitLE;
read_16bit = read_16bitLE;
}
version = read_16bit(0x06, sf); /* assumed */
if (version != 0x06 && version != 0x07) /* v6 = NFS: The Run , v7 = F&F Showndown */
goto fail;
total_subsongs = read_32bit(0x08,sf);
if (target_subsong == 0) target_subsong = 1;
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
names_size = read_32bit(0x0c,sf);
/* 0x10/14: see below */
/* 0x18: data size (all subsongs) */
offset = 0x1c + names_size; /* skip names table */
/* the following 2 sections (rarely) won't match total_subsongs */
/* section1: unknown */
{
size_t unknown_size = read_32bit(0x10,sf);
/* 0x00: usually 0, rarely 0x20? */
offset += unknown_size*0x04;
}
/* section2: samples */
{
size_t samples_size = read_32bit(0x14,sf);
/* 0x00: num_samples */
offset += samples_size*0x04;
}
/* section3: headers */
{
off_t header_offset = offset+(target_subsong-1)*0x24;
name_offset = read_32bit(header_offset+0x00, sf) + 0x1c; /* within name table */
codec = read_32bit(header_offset+0x04, sf);
sample_rate = read_32bit(header_offset+0x08, sf);
channel_count = read_32bit(header_offset+0x0c, sf);
/* 0x10: index within section1/2? */
/* 0x14: flags? 0x01 or (rarely) 0x02 */
stream_offset = read_32bit(header_offset+0x18, sf);
stream_size = read_32bit(header_offset+0x1c, sf); /* including DSP config */
num_samples = read_32bit(header_offset+0x20, sf) / channel_count; /* nibble/PCMs */
offset += total_subsongs*0x24;
}
loop_flag = 0;
start_offset = offset + stream_offset;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = num_samples;
vgmstream->num_streams = total_subsongs;
vgmstream->stream_size = stream_size;
vgmstream->meta_type = meta_WAVEBATCH;
switch(codec) {
case 0x00: /* PCM16 [NASCAR Unleashed (3DS), Solar Flux Pocket (Android)] */
vgmstream->coding_type = big_endian ? coding_PCM16BE : coding_PCM16LE;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x02;
break;
case 0x01: /* PCM8 [Cars 2 (3DS)] */
vgmstream->coding_type = coding_PCM8;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x01;
break;
case 0x02: { /* DSP [WRC FIA World Rally Championship (3DS)] */
size_t config_size = (0x20+0x14)*channel_count + (0x0c)*channel_count; /* coefs+hist + padding */
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = (stream_size - config_size) / channel_count; /* full interleave*/;
dsp_read_coefs(vgmstream,sf,start_offset+0x00,0x20+0x14,big_endian);
dsp_read_hist (vgmstream,sf,start_offset+0x20,0x14+0x20,big_endian);
start_offset += config_size;
break;
}
default:
VGM_LOG("WAVEBATCH: unknown codec %x\n", codec);
goto fail;
}
read_string(vgmstream->stream_name,STREAM_NAME_SIZE, name_offset,sf); /* always null-terminated */
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -412,7 +412,7 @@ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) {
vgmstream->num_samples = msd.num_samples;
if (!vgmstream->num_samples)
vgmstream->num_samples = (int32_t)ffmpeg_data->totalSamples; /* very wrong, from avg-br */
vgmstream->num_samples = ffmpeg_get_samples(ffmpeg_data); /* very wrong, from avg-br */
//num_samples seem to be found in the last "seek" table entry too, as: entry / channels / 2
}
@ -433,7 +433,7 @@ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) {
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
vgmstream->num_samples = (int32_t)ffmpeg_data->totalSamples;
vgmstream->num_samples = ffmpeg_get_samples(ffmpeg_data); //todo correct?
break;
}
@ -518,7 +518,7 @@ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) {
vgmstream->layout_type = layout_none;
/* FFmpeg's samples seem correct, otherwise see ogg_opus.c for getting samples. */
vgmstream->num_samples = (int32_t)((ffmpeg_codec_data*)vgmstream->codec_data)->totalSamples;
vgmstream->num_samples = ffmpeg_get_samples(vgmstream->codec_data);
break;
}

View File

@ -62,10 +62,10 @@ VGMSTREAM* init_vgmstream_xnb(STREAMFILE* sf) {
char reader_name[255+1];
size_t string_len;
uint8_t type_count;
const static char* type_sound = "Microsoft.Xna.Framework.Content.SoundEffectReader"; /* partial "fmt" chunk or XMA */
const static char* type_ogg = "SoundEffectFromOggReader"; /* has extra text info after base part */
const static char* type_song = "Microsoft.Xna.Framework.Content.SongReader"; /* references a companion .wma */
const static char* type_int32 = "Microsoft.Xna.Framework.Content.Int32Reader"; /* extra crap */
static const char* type_sound = "Microsoft.Xna.Framework.Content.SoundEffectReader"; /* partial "fmt" chunk or XMA */
static const char* type_ogg = "SoundEffectFromOggReader"; /* has extra text info after base part */
static const char* type_song = "Microsoft.Xna.Framework.Content.SongReader"; /* references a companion .wma */
static const char* type_int32 = "Microsoft.Xna.Framework.Content.Int32Reader"; /* extra crap */
type_count = read_u8(offset++, sf_h);

View File

@ -128,6 +128,9 @@ VGMSTREAM* init_vgmstream_xssb(STREAMFILE *sf) {
vgmstream->num_samples = xbox_ima_bytes_to_samples(h.stream_size, h.channels);
break;
default:
goto fail;
}
if (!vgmstream_open_stream(vgmstream, sf, h.stream_start))

View File

@ -530,7 +530,7 @@ VGMSTREAM* init_vgmstream_xwb(STREAMFILE* sf) {
/* no wma_bytes_to_samples, this should be ok */
if (!vgmstream->num_samples)
vgmstream->num_samples = (int32_t)ffmpeg_data->totalSamples;
vgmstream->num_samples = ffmpeg_get_samples(ffmpeg_data);
break;
}

View File

@ -1,87 +1,87 @@
#include "meta.h"
#include "../coding/coding.h"
/* XWMA - Microsoft WMA container [The Elder Scrolls: Skyrim (PC/X360), Hydrophobia (PC)] */
VGMSTREAM * init_vgmstream_xwma(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t fmt_offset, data_offset, first_offset = 0xc;
size_t fmt_size, data_size;
int loop_flag, channel_count;
/* checks */
/* .xwma: standard
* .xwm: The Elder Scrolls: Skyrim (PC), Blade Arcus from Shining (PC) */
if (!check_extensions(streamFile, "xwma,xwm"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x52494646) /* "RIFF" */
goto fail;
if (read_32bitBE(0x08,streamFile) != 0x58574D41) /* "XWMA" */
goto fail;
if ( !find_chunk_le(streamFile, 0x666d7420,first_offset,0, &fmt_offset,&fmt_size) ) /* "fmt "*/
goto fail;
if ( !find_chunk_le(streamFile, 0x64617461,first_offset,0, &data_offset,&data_size) ) /* "data"*/
goto fail;
channel_count = read_16bitLE(fmt_offset+0x02,streamFile);
loop_flag = 0;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = read_32bitLE(fmt_offset+0x04, streamFile);
vgmstream->meta_type = meta_XWMA;
/* the main purpose of this meta is redoing the XWMA header to:
* - redo header to fix XWMA with buggy bit rates so FFmpeg can play them ok
* - skip seek table to fix FFmpeg buggy XWMA seeking (see init_seek)
* - read num_samples correctly
*/
#ifdef VGM_USE_FFMPEG
{
uint8_t buf[0x100];
int bytes, avg_bps, block_align, wma_codec;
avg_bps = read_32bitLE(fmt_offset+0x08, streamFile);
block_align = (uint16_t)read_16bitLE(fmt_offset+0x0c, streamFile);
wma_codec = (uint16_t)read_16bitLE(fmt_offset+0x00, streamFile);
bytes = ffmpeg_make_riff_xwma(buf,0x100, wma_codec, data_size, vgmstream->channels, vgmstream->sample_rate, avg_bps, block_align);
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, data_offset,data_size);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
/* manually find total samples, why don't they put this in the header is beyond me */
{
ms_sample_data msd = {0};
msd.channels = vgmstream->channels;
msd.data_offset = data_offset;
msd.data_size = data_size;
if (wma_codec == 0x0162)
wmapro_get_samples(&msd, streamFile, block_align, vgmstream->sample_rate,0x00E0);
else
wma_get_samples(&msd, streamFile, block_align, vgmstream->sample_rate,0x001F);
vgmstream->num_samples = msd.num_samples;
if (vgmstream->num_samples == 0)
vgmstream->num_samples = (int32_t)((ffmpeg_codec_data*)vgmstream->codec_data)->totalSamples; /* from avg-br */
//num_samples seem to be found in the last "seek" table entry too, as: entry / channels / 2
}
}
#else
goto fail;
#endif
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
#include "meta.h"
#include "../coding/coding.h"
/* XWMA - Microsoft WMA container [The Elder Scrolls: Skyrim (PC/X360), Hydrophobia (PC)] */
VGMSTREAM * init_vgmstream_xwma(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t fmt_offset, data_offset, first_offset = 0xc;
size_t fmt_size, data_size;
int loop_flag, channel_count;
/* checks */
/* .xwma: standard
* .xwm: The Elder Scrolls: Skyrim (PC), Blade Arcus from Shining (PC) */
if (!check_extensions(streamFile, "xwma,xwm"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x52494646) /* "RIFF" */
goto fail;
if (read_32bitBE(0x08,streamFile) != 0x58574D41) /* "XWMA" */
goto fail;
if ( !find_chunk_le(streamFile, 0x666d7420,first_offset,0, &fmt_offset,&fmt_size) ) /* "fmt "*/
goto fail;
if ( !find_chunk_le(streamFile, 0x64617461,first_offset,0, &data_offset,&data_size) ) /* "data"*/
goto fail;
channel_count = read_16bitLE(fmt_offset+0x02,streamFile);
loop_flag = 0;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = read_32bitLE(fmt_offset+0x04, streamFile);
vgmstream->meta_type = meta_XWMA;
/* the main purpose of this meta is redoing the XWMA header to:
* - redo header to fix XWMA with buggy bit rates so FFmpeg can play them ok
* - skip seek table to fix FFmpeg buggy XWMA seeking (see init_seek)
* - read num_samples correctly
*/
#ifdef VGM_USE_FFMPEG
{
uint8_t buf[0x100];
int bytes, avg_bps, block_align, wma_codec;
avg_bps = read_32bitLE(fmt_offset+0x08, streamFile);
block_align = (uint16_t)read_16bitLE(fmt_offset+0x0c, streamFile);
wma_codec = (uint16_t)read_16bitLE(fmt_offset+0x00, streamFile);
bytes = ffmpeg_make_riff_xwma(buf,0x100, wma_codec, data_size, vgmstream->channels, vgmstream->sample_rate, avg_bps, block_align);
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, data_offset,data_size);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
/* manually find total samples, why don't they put this in the header is beyond me */
{
ms_sample_data msd = {0};
msd.channels = vgmstream->channels;
msd.data_offset = data_offset;
msd.data_size = data_size;
if (wma_codec == 0x0162)
wmapro_get_samples(&msd, streamFile, block_align, vgmstream->sample_rate,0x00E0);
else
wma_get_samples(&msd, streamFile, block_align, vgmstream->sample_rate,0x001F);
vgmstream->num_samples = msd.num_samples;
if (vgmstream->num_samples == 0)
vgmstream->num_samples = ffmpeg_get_samples(vgmstream->codec_data); /* from avg-br */
//num_samples seem to be found in the last "seek" table entry too, as: entry / channels / 2
}
}
#else
goto fail;
#endif
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -1,86 +1,86 @@
#include "meta.h"
#include "../coding/coding.h"
#include "xwma_konami_streamfile.h"
/* MSFC - Konami (Armature?) variation [Metal Gear Solid 2 HD (X360), Metal Gear Solid 3 HD (X360)] */
VGMSTREAM * init_vgmstream_xwma_konami(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count, codec, sample_rate;
size_t data_size;
STREAMFILE *temp_streamFile = NULL;
/* checks */
if (!check_extensions(streamFile,"xwma"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x58574D41) /* "XWMA" */
goto fail;
codec = read_32bitBE(0x04,streamFile);
channel_count = read_32bitBE(0x08,streamFile);
sample_rate = read_32bitBE(0x0c,streamFile);
data_size = read_32bitBE(0x10,streamFile); /* data size without padding */
loop_flag = 0;
start_offset = 0x20;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = sample_rate;
vgmstream->meta_type = meta_XWMA_KONAMI;
#ifdef VGM_USE_FFMPEG
{
uint8_t buf[0x100];
int bytes, avg_bps, block_align;
/* 0x10: related to size? */
avg_bps = read_32bitBE(0x14, streamFile);
block_align = read_32bitBE(0x18, streamFile);
/* data has padding (unrelated to KCEJ blocks) */
temp_streamFile = setup_xwma_konami_streamfile(streamFile, start_offset, block_align);
if (!temp_streamFile) goto fail;
bytes = ffmpeg_make_riff_xwma(buf,0x100, codec, data_size, channel_count, sample_rate, avg_bps, block_align);
vgmstream->codec_data = init_ffmpeg_header_offset(temp_streamFile, buf,bytes, 0x00,data_size);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
/* manually find total samples */
{
ms_sample_data msd = {0};
msd.channels = vgmstream->channels;
msd.data_offset = 0x00;
msd.data_size = data_size;
if (codec == 0x0161)
wma_get_samples(&msd, temp_streamFile, block_align, vgmstream->sample_rate,0x001F);
//else //todo not correct
// wmapro_get_samples(&msd, temp_streamFile, block_align, vgmstream->sample_rate,0x00E0);
vgmstream->num_samples = msd.num_samples;
if (vgmstream->num_samples == 0)
vgmstream->num_samples = (int32_t)((ffmpeg_codec_data*)vgmstream->codec_data)->totalSamples; /* from avg-br */
//num_samples seem to be found in the last "seek" table entry too, as: entry / channels / 2
}
}
#else
goto fail;
#endif
close_streamfile(temp_streamFile);
return vgmstream;
fail:
close_streamfile(temp_streamFile);
close_vgmstream(vgmstream);
return NULL;
}
#include "meta.h"
#include "../coding/coding.h"
#include "xwma_konami_streamfile.h"
/* MSFC - Konami (Armature?) variation [Metal Gear Solid 2 HD (X360), Metal Gear Solid 3 HD (X360)] */
VGMSTREAM * init_vgmstream_xwma_konami(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count, codec, sample_rate;
size_t data_size;
STREAMFILE *temp_streamFile = NULL;
/* checks */
if (!check_extensions(streamFile,"xwma"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x58574D41) /* "XWMA" */
goto fail;
codec = read_32bitBE(0x04,streamFile);
channel_count = read_32bitBE(0x08,streamFile);
sample_rate = read_32bitBE(0x0c,streamFile);
data_size = read_32bitBE(0x10,streamFile); /* data size without padding */
loop_flag = 0;
start_offset = 0x20;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = sample_rate;
vgmstream->meta_type = meta_XWMA_KONAMI;
#ifdef VGM_USE_FFMPEG
{
uint8_t buf[0x100];
int bytes, avg_bps, block_align;
/* 0x10: related to size? */
avg_bps = read_32bitBE(0x14, streamFile);
block_align = read_32bitBE(0x18, streamFile);
/* data has padding (unrelated to KCEJ blocks) */
temp_streamFile = setup_xwma_konami_streamfile(streamFile, start_offset, block_align);
if (!temp_streamFile) goto fail;
bytes = ffmpeg_make_riff_xwma(buf,0x100, codec, data_size, channel_count, sample_rate, avg_bps, block_align);
vgmstream->codec_data = init_ffmpeg_header_offset(temp_streamFile, buf,bytes, 0x00,data_size);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
/* manually find total samples */
{
ms_sample_data msd = {0};
msd.channels = vgmstream->channels;
msd.data_offset = 0x00;
msd.data_size = data_size;
if (codec == 0x0161)
wma_get_samples(&msd, temp_streamFile, block_align, vgmstream->sample_rate,0x001F);
//else //todo not correct
// wmapro_get_samples(&msd, temp_streamFile, block_align, vgmstream->sample_rate,0x00E0);
vgmstream->num_samples = msd.num_samples;
if (vgmstream->num_samples == 0)
vgmstream->num_samples = ffmpeg_get_samples(vgmstream->codec_data); /* from avg-br */
//num_samples seem to be found in the last "seek" table entry too, as: entry / channels / 2
}
}
#else
goto fail;
#endif
close_streamfile(temp_streamFile);
return vgmstream;
fail:
close_streamfile(temp_streamFile);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -680,6 +680,7 @@ void mixing_push_fade(VGMSTREAM* vgmstream, int ch_dst, double vol_start, double
}
else if (mix_prev->time_post < 0 || mix.time_pre < 0) {
int is_prev = 1;
/* test if prev is really cancelled by this */
if ((mix_prev->time_end > mix.time_start) ||
(mix_prev->time_post >= 0 && mix_prev->time_post > mix.time_start) ||
(mix.time_pre >= 0 && mix.time_pre < mix_prev->time_end))
@ -687,12 +688,12 @@ void mixing_push_fade(VGMSTREAM* vgmstream, int ch_dst, double vol_start, double
if (is_prev) {
/* change negative values to actual points */
if (mix_prev->time_post < 0 && mix_prev->time_post < 0) {
if (mix_prev->time_post < 0 && mix.time_pre < 0) {
mix_prev->time_post = mix_prev->time_end;
mix.time_pre = mix_prev->time_post;
}
if (mix_prev->time_post >= 0 && mix.time_pre < 0) {
if (mix_prev->time_post >= 0 && mix.time_pre < 0) {
mix.time_pre = mix_prev->time_post;
}
else if (mix_prev->time_post < 0 && mix.time_pre >= 0) {

View File

@ -525,6 +525,7 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
init_vgmstream_dsp_kwa,
init_vgmstream_ogv_3rdeye,
init_vgmstream_sspr,
init_vgmstream_piff_tpcm,
/* 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 */
@ -606,9 +607,9 @@ static VGMSTREAM* init_vgmstream_internal(STREAMFILE* sf) {
#ifdef VGM_USE_FFMPEG
/* check FFmpeg streams here, for lack of a better place */
if (vgmstream->coding_type == coding_FFmpeg) {
ffmpeg_codec_data *data = vgmstream->codec_data;
if (data && data->streamCount && !vgmstream->num_streams) {
vgmstream->num_streams = data->streamCount;
int ffmpeg_subsongs = ffmpeg_get_subsong_count(vgmstream->codec_data);
if (ffmpeg_subsongs && !vgmstream->num_streams) {
vgmstream->num_streams = ffmpeg_subsongs;
}
}
#endif
@ -1464,7 +1465,21 @@ static int get_vgmstream_file_bitrate_main(VGMSTREAM* vgmstream, bitrate_info_t*
}
if (is_unique) {
size_t stream_size;
if (br->count >= br->count_max) goto fail;
if (vgmstream->stream_size) {
/* stream_size applies to both channels but should add once and detect repeats (for current subsong) */
stream_size = get_vgmstream_file_bitrate_from_size(vgmstream->stream_size, vgmstream->sample_rate, vgmstream->num_samples);
}
else {
stream_size = get_vgmstream_file_bitrate_from_streamfile(sf_cur, vgmstream->sample_rate, vgmstream->num_samples);
}
/* possible in cases like using silence codec */
if (!stream_size)
break;
br->hash[br->count] = hash_cur;
br->subsong[br->count] = subsong_cur;
@ -1473,13 +1488,7 @@ static int get_vgmstream_file_bitrate_main(VGMSTREAM* vgmstream, bitrate_info_t*
if (p_uniques)
(*p_uniques)++;
if (vgmstream->stream_size) {
/* stream_size applies to both channels but should add once and detect repeats (for current subsong) */
bitrate += get_vgmstream_file_bitrate_from_size(vgmstream->stream_size, vgmstream->sample_rate, vgmstream->num_samples);
}
else {
bitrate += get_vgmstream_file_bitrate_from_streamfile(sf_cur, vgmstream->sample_rate, vgmstream->num_samples);
}
bitrate += stream_size;
break;
}

View File

@ -31,14 +31,6 @@ enum { VGMSTREAM_MAX_NUM_SAMPLES = 1000000000 }; /* no ~5h vgm hopefully */
//#define VGM_USE_SPEEX
#ifdef VGM_USE_VORBIS
#include <vorbis/vorbisfile.h>
#endif
#ifdef VGM_USE_MPEG
#include <mpg123/mpg123.h>
#endif
#ifdef VGM_USE_MP4V2
#define MP4V2_NO_STDINT_DEFS
#include <mp4v2/mp4v2.h>
@ -48,24 +40,12 @@ enum { VGMSTREAM_MAX_NUM_SAMPLES = 1000000000 }; /* no ~5h vgm hopefully */
#include <aacdecoder_lib.h>
#endif
#ifdef VGM_USE_MAIATRAC3PLUS
#include <maiatrac3plus.h>
#endif
#ifdef VGM_USE_FFMPEG
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswresample/swresample.h>
#endif
#include "clHCA.h"
#ifdef BUILD_VGMSTREAM
#include "coding/g72x_state.h"
#include "coding/nwa_decoder.h"
#else
#include "g72x_state.h"
#include "nwa_decoder.h"
#endif
@ -175,6 +155,7 @@ typedef enum {
coding_ASF, /* Argonaut ASF 4-bit ADPCM */
coding_DSA, /* Ocean DSA 4-bit ADPCM */
coding_XMD, /* Konami XMD 4-bit ADPCM */
coding_TANTALUS, /* Tantalus 4-bit ADPCM */
coding_PCFX, /* PC-FX 4-bit ADPCM */
coding_OKI16, /* OKI 4-bit ADPCM with 16-bit output and modified expand */
coding_OKI4S, /* OKI 4-bit ADPCM with 16-bit output and cuadruple step */
@ -763,6 +744,7 @@ typedef enum {
meta_IDSP_TOSE,
meta_DSP_KWA,
meta_OGV_3RDEYE,
meta_PIFF_TPCM,
} meta_t;
/* standard WAVEFORMATEXTENSIBLE speaker positions */
@ -1047,63 +1029,6 @@ typedef struct {
} acm_codec_data;
#ifdef VGM_USE_FFMPEG
typedef struct {
/*** IO internals ***/
STREAMFILE* streamfile;
uint64_t start; // absolute start within the streamfile
uint64_t offset; // absolute offset within the streamfile
uint64_t size; // max size within the streamfile
uint64_t logical_offset; // computed offset FFmpeg sees (including fake header)
uint64_t logical_size; // computed size FFmpeg sees (including fake header)
uint64_t header_size; // fake header (parseable by FFmpeg) prepended on reads
uint8_t* header_block; // fake header data (ie. RIFF)
/*** "public" API (read-only) ***/
// stream info
int channels;
int sampleRate;
int bitrate;
// extra info: 0 if unknown or not fixed
int64_t totalSamples; // estimated count (may not be accurate for some demuxers)
int64_t skipSamples; // number of start samples that will be skipped (encoder delay), for looping adjustments
int streamCount; // number of FFmpeg audio streams
/*** internal state ***/
// config
int channel_remap_set;
int channel_remap[32]; /* map of channel > new position */
int invert_floats_set;
int skip_samples_set; /* flag to know skip samples were manually added from vgmstream */
int force_seek; /* flags for special seeking in faulty formats */
int bad_init;
// FFmpeg context used for metadata
AVCodec *codec;
// FFmpeg decoder state
unsigned char *buffer;
AVIOContext *ioCtx;
int streamIndex;
AVFormatContext *formatCtx;
AVCodecContext *codecCtx;
AVFrame *frame; /* last decoded frame */
AVPacket *packet; /* last read data packet */
int read_packet;
int end_of_stream;
int end_of_audio;
/* sample state */
int32_t samples_discard;
int32_t samples_consumed;
int32_t samples_filled;
} ffmpeg_codec_data;
#endif
#ifdef VGM_USE_MP4V2
typedef struct {
STREAMFILE* streamfile;