Updated VGMStream to r1050-3861-g0ad117e8
parent
0a7be8ab41
commit
8622829af7
|
@ -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 */,
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) */
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "coding.h"
|
||||
#include "clHCA.h"
|
||||
|
||||
|
||||
struct hca_codec_data {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#ifndef _MPEG_DECODER_H_
|
||||
#define _MPEG_DECODER_H_
|
||||
#include <mpg123/mpg123.h>
|
||||
|
||||
#include "../vgmstream.h"
|
||||
#include "../coding/coding.h"
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*******************************************************************************/
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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_*/
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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*/
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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))" */
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue