VGMStream: Updated libvgmstream code base
Updated VGMStream to r2023-66-g6eb1f65c Signed-off-by: Christopher Snowhill <kode54@gmail.com>
This commit is contained in:
parent
f05aada52d
commit
6c0ca775cd
28 changed files with 1319 additions and 1069 deletions
|
@ -10,7 +10,6 @@ void decode_tantalus(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspac
|
|||
size_t bytes_per_frame, samples_per_frame;
|
||||
|
||||
int32_t hist1 = stream->adpcm_history1_32;
|
||||
int32_t hist2 = stream->adpcm_history2_32;
|
||||
|
||||
|
||||
/* external interleave (fixed size), mono */
|
||||
|
|
|
@ -347,6 +347,7 @@ static const char* extension_list[] = {
|
|||
"mds",
|
||||
"mdsp",
|
||||
"med",
|
||||
"mhwk",
|
||||
"mjb",
|
||||
"mi4", //fake extension for .mib (renamed, to be removed)
|
||||
"mib",
|
||||
|
@ -536,7 +537,7 @@ static const char* extension_list[] = {
|
|||
"skx",
|
||||
"slb", //txth/reserved [THE Nekomura no Hitobito (PS2)]
|
||||
"sli",
|
||||
"smc",
|
||||
"smh",
|
||||
"smk",
|
||||
"smp",
|
||||
"smv",
|
||||
|
@ -558,6 +559,7 @@ static const char* extension_list[] = {
|
|||
"spsd",
|
||||
"spw",
|
||||
"srsa",
|
||||
"srcd",
|
||||
"ss2",
|
||||
"ssd", //txth/reserved [Zack & Wiki (Wii)]
|
||||
"ssf",
|
||||
|
@ -1253,7 +1255,7 @@ static const meta_info meta_info_list[] = {
|
|||
{meta_LSF_N1NJ4N, "Gizmondo Studios Helsingborg LSF header"},
|
||||
{meta_XWAV, "feelplus XWAV header"},
|
||||
{meta_RAW_SNDS, "PC .snds raw header"},
|
||||
{meta_HYPERSCAN_KVAG, "Mattel Hyperscan KVAG"},
|
||||
{meta_KVAG, "Mattel KVAG header"},
|
||||
{meta_PSND, "Polarbit PSND header"},
|
||||
{meta_ADP_WILDFIRE, "Wildfire ADP! header"},
|
||||
{meta_QD_ADP, "Quantic Dream .ADP header"},
|
||||
|
@ -1479,6 +1481,8 @@ static const meta_info meta_info_list[] = {
|
|||
{meta_AUDIOPKG, "Inevitable .AUDIOPKG header"},
|
||||
{meta_SWAR, "Nintendo SWAR header"},
|
||||
{meta_IVB, "Metro IVB header"},
|
||||
{meta_SRCD, "Capcom SRCD header"},
|
||||
{meta_MHWK, "Broderbund MHWK header"}
|
||||
};
|
||||
|
||||
void get_vgmstream_coding_description(VGMSTREAM* vgmstream, char* out, size_t out_size) {
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
//MxCh blocked layout as used by Lego Island
|
||||
void block_update_mxch(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->next_block_offset = block_offset +
|
||||
read_32bitLE(vgmstream->current_block_offset+4,vgmstream->ch[0].streamfile)+8;
|
||||
/* skip pad blocks */
|
||||
while (
|
||||
read_32bitBE(vgmstream->current_block_offset,
|
||||
vgmstream->ch[0].streamfile) == 0x70616420)
|
||||
{
|
||||
vgmstream->current_block_offset = vgmstream->next_block_offset;
|
||||
vgmstream->next_block_offset = vgmstream->current_block_offset +
|
||||
read_32bitLE(vgmstream->current_block_offset+4,vgmstream->ch[0].streamfile)+8;
|
||||
}
|
||||
vgmstream->current_block_size =
|
||||
read_32bitLE(vgmstream->current_block_offset+4, vgmstream->ch[0].streamfile)-0xe;
|
||||
// only one channel for now
|
||||
vgmstream->ch[0].offset = vgmstream->current_block_offset+8+0xe;
|
||||
}
|
||||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
//MxCh blocked layout as used by Lego Island
|
||||
void block_update_mxch(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->next_block_offset = block_offset +
|
||||
read_32bitLE(vgmstream->current_block_offset+4,vgmstream->ch[0].streamfile)+8;
|
||||
/* skip pad blocks */
|
||||
while (
|
||||
read_32bitBE(vgmstream->current_block_offset,
|
||||
vgmstream->ch[0].streamfile) == 0x70616420)
|
||||
{
|
||||
vgmstream->current_block_offset = vgmstream->next_block_offset;
|
||||
vgmstream->next_block_offset = vgmstream->current_block_offset +
|
||||
read_32bitLE(vgmstream->current_block_offset+4,vgmstream->ch[0].streamfile)+8;
|
||||
}
|
||||
vgmstream->current_block_size =
|
||||
read_32bitLE(vgmstream->current_block_offset+4, vgmstream->ch[0].streamfile)-0xe;
|
||||
// only one channel for now
|
||||
vgmstream->ch[0].offset = vgmstream->current_block_offset+8+0xe;
|
||||
}
|
||||
|
|
|
@ -25,13 +25,13 @@ VGMSTREAM* init_vgmstream_astl(STREAMFILE* sf) {
|
|||
// 28: -1?
|
||||
// 2c: -1?
|
||||
|
||||
if (read_u16le(0x30,sf) != 0x0001) // PCM only
|
||||
return NULL;
|
||||
channels = read_u16le(0x32, sf);
|
||||
int sample_rate = read_s32le(0x34,sf);
|
||||
// 38: bitrate
|
||||
// 3a: block size
|
||||
// 3c: bps
|
||||
// fmt-like
|
||||
int format = read_u16le(0x30 + 0x00, sf);
|
||||
channels = read_u16le(0x30 + 0x02, sf);
|
||||
int sample_rate = read_s32le(0x30 + 0x04, sf);
|
||||
// 08: avg bitrate
|
||||
// 0a: block size
|
||||
// 0e: bps
|
||||
|
||||
loop_flag = 0; // unlike X360 no apparent loop info in the files
|
||||
|
||||
|
@ -42,11 +42,51 @@ VGMSTREAM* init_vgmstream_astl(STREAMFILE* sf) {
|
|||
|
||||
vgmstream->meta_type = meta_ASTL;
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->num_samples = pcm16_bytes_to_samples(data_size, channels);
|
||||
|
||||
vgmstream->coding_type = coding_PCM16LE;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x2;
|
||||
switch(format) {
|
||||
case 0x0001:
|
||||
vgmstream->num_samples = pcm16_bytes_to_samples(data_size, channels);
|
||||
vgmstream->coding_type = coding_PCM16LE;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x2;
|
||||
break;
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
case 0xFFFE: { // WAVEFORMATEXTENSIBLE
|
||||
uint32_t avg_bitrate = read_u32le(0x30 + 0x08, sf);
|
||||
uint16_t block_size = read_u16le(0x30 + 0x0c, sf);
|
||||
uint32_t channel_layout = read_u32le(0x30 + 0x14, sf);
|
||||
// actually a GUID but first 32b matches fmt (0x0162 / STATIC_KSDATAFORMAT_SUBTYPE_WMAUDIO3 only?)
|
||||
uint32_t xwma_format = read_u32le(0x30 + 0x18, sf);
|
||||
|
||||
uint32_t dpds_offset = 0x30 + 0x28;
|
||||
uint32_t dpds_size;
|
||||
uint32_t offset = dpds_offset;
|
||||
// TODO channel layout
|
||||
|
||||
vgmstream->codec_data = init_ffmpeg_xwma(sf, start_offset, data_size, xwma_format, channels, sample_rate, avg_bitrate, block_size);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
vgmstream->channel_layout = channel_layout;
|
||||
|
||||
// somehow there is no dpds size, so find last value before null padding
|
||||
while (offset < start_offset) {
|
||||
uint32_t sample = read_u32le(offset, sf);
|
||||
if (sample == 0)
|
||||
break;
|
||||
offset += 0x04;
|
||||
}
|
||||
|
||||
dpds_size = offset - dpds_offset;
|
||||
vgmstream->num_samples = xwma_dpds_get_samples(sf, dpds_offset, dpds_size, channels, false);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||
goto fail;
|
||||
|
|
|
@ -9,7 +9,7 @@ VGMSTREAM * init_vgmstream_bar(STREAMFILE *streamFile) {
|
|||
off_t start_offset;
|
||||
off_t ch2_start_offset;
|
||||
int loop_flag;
|
||||
int channel_count;
|
||||
int channel_count;
|
||||
long file_size;
|
||||
|
||||
|
||||
|
|
|
@ -175,10 +175,10 @@ VGMSTREAM* init_vgmstream_ea_swvr(STREAMFILE* sf) {
|
|||
do {
|
||||
block_update(vgmstream->next_block_offset,vgmstream);
|
||||
switch(vgmstream->coding_type) {
|
||||
case coding_PSX: num_samples = ps_bytes_to_samples(vgmstream->current_block_size,1); break;
|
||||
case coding_NGC_DSP: num_samples = dsp_bytes_to_samples(vgmstream->current_block_size,1); break;
|
||||
case coding_PSX: num_samples = ps_bytes_to_samples(vgmstream->current_block_size,1); break;
|
||||
case coding_NGC_DSP: num_samples = dsp_bytes_to_samples(vgmstream->current_block_size,1); break;
|
||||
case coding_PCM8_U_int: num_samples = pcm_bytes_to_samples(vgmstream->current_block_size,1,8); break;
|
||||
default: num_samples = 0; break;
|
||||
default: num_samples = 0; break;
|
||||
}
|
||||
vgmstream->num_samples += num_samples;
|
||||
|
||||
|
|
|
@ -50,11 +50,18 @@ VGMSTREAM* init_vgmstream_fsb5_fev_bank(STREAMFILE* sf) {
|
|||
goto fail;
|
||||
|
||||
switch(chunk_type) {
|
||||
case 0x4C495354: /* "LIST" with "SNDH" (usually v0x28 but also in Fall Guys's BNK_Music_RoundReveal) */
|
||||
if (read_u32be(offset + 0x04, sf) == 0x534E4448) {
|
||||
case 0x4C495354: /* "LIST" */
|
||||
// "SNDH" (usually v0x28 but also in Fall Guys's BNK_Music_RoundReveal)
|
||||
if (read_u32be(offset + 0x04, sf) == get_id32be("SNDH")) {
|
||||
bank_offset = offset + 0x0c;
|
||||
bank_size = read_s32le(offset + 0x08,sf);
|
||||
}
|
||||
|
||||
// multiple CrankcaseAudio REV ADM3 [Rennsport (PC)]
|
||||
if (read_u32be(offset + 0x00, sf) == get_id32be("PEFX")) {
|
||||
bank_offset = offset;
|
||||
bank_size = chunk_size;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x534E4448: /* "SNDH" */
|
||||
|
|
|
@ -1572,6 +1572,9 @@ static const hcakey_info hcakey_list[] = {
|
|||
// Sand Land (multi)
|
||||
{910990237314908160}, // 0CA47CCB51010000
|
||||
|
||||
// Patapon 1 & 2 Reloaded (PC)
|
||||
{3316332033470531258}, // 2E05FA69EC4286BA
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,44 +1,45 @@
|
|||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
|
||||
/* IDSP - from Inevitable Entertainment games [Defender (GC)] */
|
||||
VGMSTREAM * init_vgmstream_idsp_ie(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag, channel_count;
|
||||
|
||||
|
||||
/* checks */
|
||||
if ( !check_extensions(streamFile,"idsp") )
|
||||
goto fail;
|
||||
if (read_32bitBE(0x00,streamFile) != 0x49445350) /* "IDSP" */
|
||||
goto fail;
|
||||
|
||||
loop_flag = 0;
|
||||
channel_count = read_32bitBE(0x0C,streamFile);
|
||||
if (channel_count > 2) goto fail;
|
||||
start_offset = 0x70;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_IDSP_IE;
|
||||
vgmstream->sample_rate = read_32bitBE(0x08,streamFile);
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->num_samples = dsp_bytes_to_samples(read_32bitBE(0x04,streamFile), channel_count);
|
||||
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = read_32bitBE(0x10,streamFile);
|
||||
dsp_read_coefs_be(vgmstream,streamFile,0x14,0x2E);
|
||||
|
||||
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"
|
||||
|
||||
|
||||
/* IDSP - from Inevitable Entertainment games [Defender (GC)] */
|
||||
VGMSTREAM* init_vgmstream_idsp_ie(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag, channels;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!is_id32be(0x00, sf, "IDSP"))
|
||||
return NULL;
|
||||
if (!check_extensions(sf,"idsp"))
|
||||
return NULL;
|
||||
|
||||
channels = read_s32be(0x0C,sf);
|
||||
if (channels > 2) return NULL;
|
||||
|
||||
loop_flag = 0;
|
||||
start_offset = 0x70;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channels,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_IDSP_IE;
|
||||
vgmstream->sample_rate = read_s32be(0x08,sf);
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->num_samples = dsp_bytes_to_samples(read_u32be(0x04,sf), channels);
|
||||
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = read_u32be(0x10,sf);
|
||||
dsp_read_coefs_be(vgmstream, sf, 0x14, 0x2E);
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -1,115 +1,113 @@
|
|||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* .IMC - from iNiS Gitaroo Man (PS2) */
|
||||
VGMSTREAM * init_vgmstream_imc(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag, channel_count, sample_rate, interleave, blocks;
|
||||
size_t file_size, data_size;
|
||||
|
||||
|
||||
/* checks */
|
||||
/* .imc: extension from the main container */
|
||||
if (!check_extensions(streamFile, "imc"))
|
||||
goto fail;
|
||||
|
||||
channel_count = read_32bitLE(0x00, streamFile);
|
||||
sample_rate = read_32bitLE(0x04, streamFile);
|
||||
interleave = read_32bitLE(0x08, streamFile) * 0x10; /* number of frames in a block */
|
||||
blocks = read_32bitLE(0x0c, streamFile); /* number of interleave blocks (even in mono) */
|
||||
|
||||
file_size = get_streamfile_size(streamFile);
|
||||
loop_flag = 0;
|
||||
start_offset = 0x10;
|
||||
|
||||
/* extra checks since the header is so simple */
|
||||
if (channel_count < 1 || channel_count > 8)
|
||||
goto fail;
|
||||
if (sample_rate < 11025 || sample_rate > 48000)
|
||||
/* game can play 11025, 16000, 22050, 32000, 44100, 48000. Anything else will be
|
||||
silent in-game. ST10.IMC subsongs 42-47 use 22000, those are unused silent audio */
|
||||
goto fail;
|
||||
if (interleave*blocks + start_offset != file_size)
|
||||
goto fail;
|
||||
|
||||
data_size = file_size - start_offset;
|
||||
data_size -= ps_find_padding(streamFile, start_offset, data_size, channel_count, interleave, 0);
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_IMC;
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->num_samples = ps_bytes_to_samples(data_size, channel_count);
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = interleave;
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ****************************************************************************** */
|
||||
|
||||
/* .IMC in containers */
|
||||
VGMSTREAM * init_vgmstream_imc_container(STREAMFILE *streamFile) {
|
||||
VGMSTREAM *vgmstream = NULL;
|
||||
STREAMFILE *temp_streamFile = NULL;
|
||||
off_t header_offset, subfile_offset, next_offset, name_offset;
|
||||
size_t subfile_size;
|
||||
int total_subsongs, target_subsong = streamFile->stream_index;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "imc"))
|
||||
goto fail;
|
||||
|
||||
total_subsongs = read_32bitLE(0x00, streamFile);
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||
|
||||
|
||||
header_offset = 0x04 + 0x20*(target_subsong-1);
|
||||
|
||||
name_offset = header_offset + 0x00;
|
||||
/* 0x08: flags? (0x702ADE77|0x002ADE77|0x20000000|etc) */
|
||||
/* 0x0c: same for all songs in single .imc but varies between .imc */
|
||||
subfile_offset = read_32bitLE(header_offset + 0x10,streamFile);
|
||||
/* 0x14: flags/size? (0xF0950000|0x3CFA1200|etc) */
|
||||
/* 0x18: same for all songs in single .imc but varies between .imc */
|
||||
/* 0x1c: flags? (0 or 2) */
|
||||
|
||||
if (target_subsong == total_subsongs) {
|
||||
next_offset = get_streamfile_size(streamFile);
|
||||
}
|
||||
else {
|
||||
next_offset = read_32bitLE(header_offset + 0x20 + 0x10,streamFile);
|
||||
}
|
||||
subfile_size = next_offset - subfile_offset;
|
||||
|
||||
|
||||
temp_streamFile = setup_subfile_streamfile(streamFile, subfile_offset,subfile_size, NULL);
|
||||
if (!temp_streamFile) goto fail;
|
||||
|
||||
vgmstream = init_vgmstream_imc(temp_streamFile);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
close_streamfile(temp_streamFile);
|
||||
vgmstream->num_streams = total_subsongs;
|
||||
read_string(vgmstream->stream_name,0x08+1, name_offset,streamFile);
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* .IMC (subfile) - from iNiS Gitaroo Man (PS2) */
|
||||
VGMSTREAM* init_vgmstream_imc(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
|
||||
/* checks */
|
||||
/* .imc: extension from the main container */
|
||||
if (!check_extensions(sf, "imc"))
|
||||
return NULL;
|
||||
|
||||
int channels = read_s32le(0x00, sf);
|
||||
int sample_rate = read_s32le(0x04, sf);
|
||||
int interleave = read_s32le(0x08, sf) * 0x10; // number of frames in a block
|
||||
int blocks = read_s32le(0x0c, sf); // number of interleave blocks (even in mono)
|
||||
|
||||
uint32_t start_offset = 0x10;
|
||||
uint32_t file_size = get_streamfile_size(sf);
|
||||
bool loop_flag = false;
|
||||
|
||||
// extra checks since the header is so simple
|
||||
if (channels < 1 || channels > 8)
|
||||
return NULL;
|
||||
|
||||
// Game can play 11025, 16000, 22050, 32000, 44100, 48000. Anything else will be
|
||||
// silent in-game. ST10.IMC subsongs 42-47 use 22000, those are unused silent audio
|
||||
if (sample_rate < 11025 || sample_rate > 48000)
|
||||
return NULL;
|
||||
|
||||
if (interleave * blocks + start_offset != file_size)
|
||||
return NULL;
|
||||
|
||||
uint32_t data_size = file_size - start_offset;
|
||||
data_size -= ps_find_padding(sf, start_offset, data_size, channels, interleave, 0);
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channels, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_IMC;
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->num_samples = ps_bytes_to_samples(data_size, channels);
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = interleave;
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ****************************************************************************** */
|
||||
|
||||
/* .IMC in containers */
|
||||
VGMSTREAM* init_vgmstream_imc_container(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
STREAMFILE* temp_sf = NULL;
|
||||
off_t header_offset, subfile_offset, next_offset, name_offset;
|
||||
size_t subfile_size;
|
||||
int total_subsongs, target_subsong = sf->stream_index;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(sf, "imc"))
|
||||
return NULL;
|
||||
|
||||
total_subsongs = read_s32le(0x00, sf);
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||
|
||||
|
||||
header_offset = 0x04 + 0x20 * (target_subsong - 1);
|
||||
|
||||
name_offset = header_offset + 0x00;
|
||||
/* 0x08: flags? (0x702ADE77|0x002ADE77|0x20000000|etc) */
|
||||
/* 0x0c: same for all songs in single .imc but varies between .imc */
|
||||
subfile_offset = read_u32le(header_offset + 0x10,sf);
|
||||
/* 0x14: flags/size? (0xF0950000|0x3CFA1200|etc) */
|
||||
/* 0x18: same for all songs in single .imc but varies between .imc */
|
||||
/* 0x1c: flags? (0 or 2) */
|
||||
|
||||
if (target_subsong == total_subsongs) {
|
||||
next_offset = get_streamfile_size(sf);
|
||||
}
|
||||
else {
|
||||
next_offset = read_u32le(header_offset + 0x20 + 0x10,sf);
|
||||
}
|
||||
subfile_size = next_offset - subfile_offset;
|
||||
|
||||
|
||||
temp_sf = setup_subfile_streamfile(sf, subfile_offset,subfile_size, NULL);
|
||||
if (!temp_sf) goto fail;
|
||||
|
||||
vgmstream = init_vgmstream_imc(temp_sf);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->num_streams = total_subsongs;
|
||||
read_string(vgmstream->stream_name,0x08+1, name_offset,sf);
|
||||
|
||||
close_streamfile(temp_sf);
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_sf);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
|
32
Frameworks/vgmstream/vgmstream/src/meta/kvag.c
Normal file
32
Frameworks/vgmstream/vgmstream/src/meta/kvag.c
Normal file
|
@ -0,0 +1,32 @@
|
|||
#include "meta.h"
|
||||
#include "../util/meta_utils.h"
|
||||
|
||||
/* KVAG - Mattel Hyperscan games [Marvel Heroes (Hyperscan), X-Men (Hyperscan)] */
|
||||
VGMSTREAM* init_vgmstream_hyperscan_kvag(STREAMFILE* sf) {
|
||||
|
||||
/* checks */
|
||||
if (!is_id32be(0x00,sf, "KVAG"))
|
||||
return NULL;
|
||||
if (!check_extensions(sf,"bvg"))
|
||||
return NULL;
|
||||
|
||||
meta_header_t h = {0};
|
||||
h.meta = meta_KVAG;
|
||||
|
||||
h.stream_size = read_u32le(0x04, sf);
|
||||
h.sample_rate = read_s32le(0x08, sf);
|
||||
h.channels = read_s16le(0x0c, sf) + 1;
|
||||
h.stream_offset = 0x0e;
|
||||
|
||||
if (h.channels > 2) // 2ch is rare [Ben 10's Theme22ks]
|
||||
return NULL;
|
||||
|
||||
h.num_samples = ima_bytes_to_samples(h.stream_size, h.channels);
|
||||
|
||||
h.coding = coding_DVI_IMA;
|
||||
h.layout = layout_none;
|
||||
h.open_stream = true;
|
||||
h.sf = sf;
|
||||
|
||||
return alloc_metastream(&h);
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* Mattel Hyperscan,
|
||||
- Place all metas for this console here (there are just 5 games) */
|
||||
VGMSTREAM * init_vgmstream_hyperscan_kvag(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
off_t start_offset;
|
||||
int loop_flag = 0;
|
||||
int channel_count;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("bvg",filename_extension(filename))) goto fail;
|
||||
|
||||
/* check header */
|
||||
if (read_32bitBE(0x00,streamFile) != 0x4B564147) /* "KVAG" */
|
||||
goto fail;
|
||||
|
||||
channel_count = 1;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
start_offset = 0xE;
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = read_32bitLE(0x8,streamFile);
|
||||
vgmstream->coding_type = coding_DVI_IMA;
|
||||
vgmstream->num_samples = read_32bitLE(0x4,streamFile)*2;
|
||||
|
||||
#if 0
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = (read_32bitLE(0x08,streamFile)-1)*28;
|
||||
vgmstream->loop_end_sample = (read_32bitLE(0x0c,streamFile)-1)*28;
|
||||
}
|
||||
#endif
|
||||
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->meta_type = meta_HYPERSCAN_KVAG;
|
||||
|
||||
/* open the file for reading */
|
||||
{
|
||||
int i;
|
||||
STREAMFILE * file;
|
||||
file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!file) goto fail;
|
||||
for (i=0;i<channel_count;i++) {
|
||||
vgmstream->ch[i].streamfile = file;
|
||||
|
||||
vgmstream->ch[i].channel_start_offset=
|
||||
vgmstream->ch[i].offset=start_offset+
|
||||
vgmstream->interleave_block_size*i;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
|
@ -1,58 +1,54 @@
|
|||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* Maxis XA - found in Sim City 3000 (PC), The Sims 2 (PC) */
|
||||
VGMSTREAM * init_vgmstream_maxis_xa(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int avg_byte_rate, channel_count, loop_flag, resolution, sample_align, sample_rate;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
if (!check_extensions(streamFile,"xa"))
|
||||
goto fail;
|
||||
|
||||
/* check header */
|
||||
if ((read_16bitBE(0x00,streamFile) != 0x5841)) /* "XA" */
|
||||
goto fail;
|
||||
|
||||
/* check format tag */
|
||||
if ((read_16bitLE(0x08,streamFile) != 0x0001))
|
||||
goto fail;
|
||||
|
||||
channel_count = read_16bitLE(0x0A,streamFile);
|
||||
sample_rate = read_32bitLE(0x0C,streamFile);
|
||||
avg_byte_rate = read_32bitLE(0x10,streamFile);
|
||||
sample_align = read_16bitLE(0x14,streamFile);
|
||||
resolution = read_16bitLE(0x16,streamFile);
|
||||
|
||||
/* check alignment */
|
||||
if (sample_align != (resolution/8)*channel_count)
|
||||
goto fail;
|
||||
|
||||
/* check average byte rate */
|
||||
if (avg_byte_rate != sample_rate*sample_align)
|
||||
goto fail;
|
||||
|
||||
loop_flag = 0;
|
||||
start_offset = 0x18;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->num_samples = read_32bitLE(0x04,streamFile)/2/channel_count;
|
||||
|
||||
vgmstream->meta_type = meta_MAXIS_XA;
|
||||
vgmstream->coding_type = coding_MAXIS_XA;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
/* open streams */
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* Maxis XA - found in Sim City 3000 (PC), The Sims 2 (PC) */
|
||||
VGMSTREAM* init_vgmstream_maxis_xa(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
|
||||
/* checks */
|
||||
if ((read_u32be(0x00,sf) & 0xFFFF0000) != get_id32be("XA\0\0")) // 02: "I"/"J"/null (version?)
|
||||
return NULL;
|
||||
|
||||
uint32_t pcm_size = read_u32le(0x04,sf);
|
||||
if (read_u16le(0x08,sf) != 0x0001)
|
||||
return NULL;
|
||||
|
||||
if (!check_extensions(sf,"xa"))
|
||||
return NULL;
|
||||
|
||||
int channels = read_s16le(0x0A,sf);
|
||||
int sample_rate = read_s32le(0x0C,sf);
|
||||
int avg_byte_rate = read_s32le(0x10,sf);
|
||||
int sample_align = read_u16le(0x14,sf);
|
||||
int resolution = read_u16le(0x16,sf);
|
||||
|
||||
/* check alignment */
|
||||
if (sample_align != (resolution / 8) * channels)
|
||||
return NULL;
|
||||
|
||||
/* check average byte rate */
|
||||
if (avg_byte_rate != sample_rate * sample_align)
|
||||
return NULL;
|
||||
|
||||
off_t start_offset = 0x18;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channels, false);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->num_samples = pcm_size / sizeof(short) / channels;
|
||||
|
||||
vgmstream->meta_type = meta_MAXIS_XA;
|
||||
vgmstream->coding_type = coding_MAXIS_XA;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
/* open streams */
|
||||
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -701,7 +701,7 @@ VGMSTREAM * init_vgmstream_msb_msh(STREAMFILE * streamFile);
|
|||
|
||||
VGMSTREAM * init_vgmstream_txtp(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_smc_smh(STREAMFILE * streamFile);
|
||||
VGMSTREAM* init_vgmstream_smh_smc(STREAMFILE* sf);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ppst(STREAMFILE *streamFile);
|
||||
|
||||
|
@ -1035,4 +1035,8 @@ VGMSTREAM* init_vgmstream_swar(STREAMFILE* sf);
|
|||
|
||||
VGMSTREAM* init_vgmstream_ivb(STREAMFILE* sf);
|
||||
|
||||
VGMSTREAM* init_vgmstream_mhwk(STREAMFILE* sf);
|
||||
|
||||
VGMSTREAM* init_vgmstream_srcd(STREAMFILE* sf);
|
||||
|
||||
#endif
|
||||
|
|
104
Frameworks/vgmstream/vgmstream/src/meta/mhwk.c
Normal file
104
Frameworks/vgmstream/vgmstream/src/meta/mhwk.c
Normal file
|
@ -0,0 +1,104 @@
|
|||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* MHWK - Broderbund's Mohawk engine (.mhk) */
|
||||
VGMSTREAM* init_vgmstream_mhwk(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
off_t start_offset = 0;
|
||||
int loop_flag = 0, channels = 0, sample_rate = 0, format = 0;
|
||||
int32_t num_samples = 0, loop_start = 0, loop_end = 0;
|
||||
off_t current_offset;
|
||||
uint32_t chunk_id;
|
||||
uint32_t chunk_size;
|
||||
|
||||
/* Check for MHWK magic word */
|
||||
if (!is_id32be(0x00, sf, "MHWK"))
|
||||
return NULL;
|
||||
|
||||
if (!check_extensions(sf, "mhk"))
|
||||
return NULL;
|
||||
|
||||
/* Check for WAVE magic word, which follows the MHWK header */
|
||||
if (!is_id32be(0x08, sf, "WAVE"))
|
||||
goto fail;
|
||||
|
||||
current_offset = 0x0C;
|
||||
|
||||
while (current_offset < get_streamfile_size(sf)) {
|
||||
chunk_id = read_u32be(current_offset, sf);
|
||||
chunk_size = read_u32be(current_offset + 0x04, sf);
|
||||
current_offset += 0x08;
|
||||
|
||||
if (chunk_id == get_id32be("Cue#")) {
|
||||
current_offset += chunk_size;
|
||||
continue;
|
||||
}
|
||||
else if (chunk_id == get_id32be("ADPC")) {
|
||||
current_offset += chunk_size;
|
||||
continue;
|
||||
}
|
||||
else if (chunk_id == get_id32be("Data")) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* Data chunk header */
|
||||
|
||||
/* Header size is consistently 20 bytes from analysis */
|
||||
sample_rate = read_u16be(current_offset + 0x00, sf);
|
||||
num_samples = read_u32be(current_offset + 0x02, sf);
|
||||
/* 0x06: sample width (1 byte), 0x07: channels (1 byte) */
|
||||
channels = read_u8(current_offset + 0x07, sf);
|
||||
format = read_u16be(current_offset + 0x08, sf);
|
||||
|
||||
if (read_u16be(current_offset + 0x0A, sf) == 0xFFFF) {
|
||||
loop_flag = 1;
|
||||
loop_start = read_u32be(current_offset + 0x0C, sf);
|
||||
loop_end = read_u32be(current_offset + 0x10, sf);
|
||||
}
|
||||
|
||||
/* The actual audio data starts after the header's 20 bytes not 28 bytes */
|
||||
start_offset = current_offset + 0x14;
|
||||
|
||||
vgmstream = allocate_vgmstream(channels, loop_flag);
|
||||
if (!vgmstream)
|
||||
goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_MHWK;
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->num_samples = num_samples;
|
||||
vgmstream->loop_start_sample = loop_start;
|
||||
vgmstream->loop_end_sample = loop_end;
|
||||
|
||||
/* Determine coding type based on format ID */
|
||||
switch (format) {
|
||||
|
||||
//Myst 1993
|
||||
case 0x0000: /* 8-bit unsigned PCM. Default */
|
||||
vgmstream->coding_type = coding_PCM8_U;
|
||||
vgmstream->layout_type = layout_interleave; // Usually mono.
|
||||
vgmstream->interleave_block_size = 0x01;
|
||||
break;
|
||||
|
||||
//Carmen Sandiego: Word Detective
|
||||
case 0x0001: /* IMA ADPCM */
|
||||
vgmstream->coding_type = coding_IMA;
|
||||
vgmstream->layout_type = layout_none;
|
||||
break;
|
||||
|
||||
default: /* Unknown format */
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||
goto fail;
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
|
@ -7,37 +7,37 @@
|
|||
static VGMSTREAM* init_vgmstream_mp4_aac_offset(STREAMFILE* sf, uint64_t start, uint64_t size);
|
||||
|
||||
VGMSTREAM* init_vgmstream_mp4_aac(STREAMFILE* sf) {
|
||||
return init_vgmstream_mp4_aac_offset( sf, 0x00, get_streamfile_size(sf));
|
||||
return init_vgmstream_mp4_aac_offset( sf, 0x00, get_streamfile_size(sf));
|
||||
}
|
||||
|
||||
static VGMSTREAM* init_vgmstream_mp4_aac_offset(STREAMFILE* sf, uint64_t start, uint64_t size) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
mp4_aac_codec_data* data = NULL;
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
mp4_aac_codec_data* data = NULL;
|
||||
|
||||
data = init_mp4_aac(sf);
|
||||
if (!data) goto fail;
|
||||
data = init_mp4_aac(sf);
|
||||
if (!data) goto fail;
|
||||
|
||||
int channels = mp4_aac_get_channels(data);
|
||||
int channels = mp4_aac_get_channels(data);
|
||||
|
||||
vgmstream = allocate_vgmstream(channels, 0);
|
||||
if (!vgmstream) goto fail;
|
||||
vgmstream = allocate_vgmstream(channels, 0);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = mp4_aac_get_sample_rate(data);
|
||||
vgmstream->num_samples = mp4_aac_get_samples(data);
|
||||
vgmstream->sample_rate = mp4_aac_get_sample_rate(data);
|
||||
vgmstream->num_samples = mp4_aac_get_samples(data);
|
||||
|
||||
vgmstream->codec_data = data;
|
||||
vgmstream->coding_type = coding_MP4_AAC;
|
||||
vgmstream->codec_data = data;
|
||||
vgmstream->coding_type = coding_MP4_AAC;
|
||||
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->meta_type = meta_MP4;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->meta_type = meta_MP4;
|
||||
|
||||
return vgmstream;
|
||||
return vgmstream;
|
||||
fail:
|
||||
free_mp4_aac(data);
|
||||
if (vgmstream) {
|
||||
vgmstream->codec_data = NULL;
|
||||
close_vgmstream(vgmstream);
|
||||
}
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,218 +1,218 @@
|
|||
//MxSt files ripped from Jukebox.si in Lego Island
|
||||
#include "meta.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "../util.h"
|
||||
|
||||
VGMSTREAM * init_vgmstream_pc_mxst(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
|
||||
int loop_flag=0;
|
||||
int bits_per_sample;
|
||||
int channel_count;
|
||||
int sample_rate,bytes_per_second;
|
||||
long sample_count;
|
||||
int i;
|
||||
off_t file_size;
|
||||
off_t chunk_list_size=-1;
|
||||
off_t start_offset;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("mxst",filename_extension(filename))) goto fail;
|
||||
|
||||
/* looping info not found yet */
|
||||
//loop_flag = get_streamfile_size(streamFile) > 700000;
|
||||
|
||||
/* check MxSt header */
|
||||
if (0x4d785374 != read_32bitBE(0, streamFile)) goto fail;
|
||||
file_size = read_32bitLE(4, streamFile) + 8;
|
||||
if (file_size != get_streamfile_size(streamFile)) goto fail;
|
||||
|
||||
/* read chunks */
|
||||
{
|
||||
off_t MxDa=-1; /* points inside the MxDa chunk */
|
||||
off_t MxCh=-1; /* point at start of the first MxCh chunk */
|
||||
off_t chunk_offset = 8;
|
||||
uint32_t stream_id;
|
||||
while (chunk_offset < file_size)
|
||||
{
|
||||
uint32_t chunk_size = (read_32bitLE(chunk_offset+4, streamFile)+1)/2*2;
|
||||
switch (read_32bitBE(chunk_offset, streamFile))
|
||||
{
|
||||
case 0x4d784f62: /* MxOb */
|
||||
/* not interesting for playback */
|
||||
break;
|
||||
case 0x20574156: /* " WAV" */
|
||||
if (chunk_size == 1)
|
||||
chunk_size = 8;
|
||||
break;
|
||||
case 0x4c495354: /* LIST */
|
||||
{
|
||||
off_t first_item_offset = chunk_offset+0x14;
|
||||
off_t list_chunk_offset = first_item_offset+
|
||||
read_32bitLE(chunk_offset+0x10,streamFile);
|
||||
|
||||
if (read_32bitBE(chunk_offset+0x8,streamFile) == 0x4d784461) /* MxDa */
|
||||
MxDa = first_item_offset;
|
||||
else
|
||||
goto fail;
|
||||
|
||||
if (read_32bitBE(chunk_offset+0xC,streamFile) ==
|
||||
0x4d784368) /* MxCh */
|
||||
{
|
||||
MxCh = list_chunk_offset;
|
||||
chunk_list_size = chunk_size - (list_chunk_offset-(chunk_offset+8));
|
||||
}
|
||||
else
|
||||
goto fail;
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
chunk_offset += 8 + chunk_size;
|
||||
if (chunk_offset > file_size) goto fail;
|
||||
}
|
||||
|
||||
if (MxDa == -1 || MxCh == -1 || chunk_list_size == -1) goto fail;
|
||||
|
||||
/* parse MxDa */
|
||||
{
|
||||
/* ??? */
|
||||
if (0 != read_16bitLE(MxDa+0x00,streamFile)) goto fail;
|
||||
stream_id = read_32bitLE(MxDa+0x2,streamFile);
|
||||
/* First sample (none in MxDa block) */
|
||||
if (-1 != read_32bitLE(MxDa+0x06,streamFile)) goto fail;
|
||||
/* size of format data */
|
||||
if (0x18 != read_32bitLE(MxDa+0x0a,streamFile)) goto fail;
|
||||
/* PCM */
|
||||
if (1 != read_16bitLE(MxDa+0x0e,streamFile)) goto fail;
|
||||
/* channel count */
|
||||
channel_count = read_16bitLE(MxDa+0x10,streamFile);
|
||||
/* only mono known */
|
||||
if (1 != channel_count) goto fail;
|
||||
sample_rate = read_32bitLE(MxDa+0x12,streamFile);
|
||||
bits_per_sample = read_16bitLE(MxDa+0x1c,streamFile);
|
||||
/* bytes per second */
|
||||
bytes_per_second = read_32bitLE(MxDa+0x16,streamFile);
|
||||
if (bits_per_sample/8*channel_count*sample_rate != bytes_per_second) goto fail;
|
||||
/* block align */
|
||||
if (bits_per_sample/8*channel_count !=
|
||||
read_16bitLE(MxDa+0x1a,streamFile)) goto fail;
|
||||
sample_count = read_32bitLE(MxDa+0x1e,streamFile)/(bits_per_sample/8)/channel_count;
|
||||
/* 2c? data offset in normal RIFF WAVE? */
|
||||
if (0x2c != read_32bitLE(MxDa+0x22,streamFile)) goto fail;
|
||||
}
|
||||
|
||||
/* parse through all MxCh for consistency check */
|
||||
{
|
||||
long samples = 0;
|
||||
int split_frames_seen = 0;
|
||||
off_t MxCh_offset = MxCh;
|
||||
while (MxCh_offset < MxCh+chunk_list_size)
|
||||
{
|
||||
uint16_t flags;
|
||||
if (read_32bitBE(MxCh_offset,streamFile)!=0x70616420) /*pad*/
|
||||
{
|
||||
if (read_32bitBE(MxCh_offset,streamFile)!=0x4d784368) /*MxCh*/
|
||||
goto fail;
|
||||
|
||||
flags = read_16bitLE(MxCh_offset+8+0,streamFile);
|
||||
|
||||
if (read_32bitLE(MxCh_offset+8+2,streamFile)!=stream_id)
|
||||
goto fail;
|
||||
|
||||
if (flags & 0x10)
|
||||
{
|
||||
split_frames_seen ++;
|
||||
if (split_frames_seen == 1)
|
||||
{
|
||||
if (read_32bitLE(MxCh_offset+8+6,streamFile)!=(samples*UINT64_C(1000)+sample_rate-1)/sample_rate)
|
||||
goto fail;
|
||||
}
|
||||
else if (split_frames_seen == 2)
|
||||
{
|
||||
if ( read_32bitLE(MxCh_offset+8+0xa,streamFile)!=
|
||||
read_32bitLE(MxCh_offset+4,streamFile)-0xe ) goto fail;
|
||||
split_frames_seen = 0;
|
||||
}
|
||||
else goto fail;
|
||||
}
|
||||
|
||||
if (!(flags & 0x10))
|
||||
{
|
||||
if (split_frames_seen != 0)
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
if (read_32bitLE(MxCh_offset+8+6,streamFile)!=(samples*UINT64_C(1000)+sample_rate-1)/sample_rate)
|
||||
goto fail;
|
||||
|
||||
if ( read_32bitLE(MxCh_offset+8+0xa,streamFile)!=
|
||||
read_32bitLE(MxCh_offset+4,streamFile)-0xe ) goto fail;
|
||||
}
|
||||
samples += (read_32bitLE(MxCh_offset+4,streamFile)-0xe)/(bits_per_sample/8/channel_count);
|
||||
|
||||
}
|
||||
MxCh_offset += 8 + (read_32bitLE(MxCh_offset+4,streamFile)+1)/2*2;
|
||||
if (MxCh_offset > MxCh+chunk_list_size) goto fail;
|
||||
}
|
||||
//printf("samples=%d sample_count=%d\n",samples,sample_count);
|
||||
//samples = (samples * (bits_per_sample/8) * channel_count + 31)/32*32/(bits_per_sample/8)/channel_count;
|
||||
if (samples < sample_count)
|
||||
{
|
||||
sample_count = samples;
|
||||
}
|
||||
if (samples != sample_count) goto fail;
|
||||
}
|
||||
|
||||
start_offset = MxCh;
|
||||
}
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->layout_type = layout_blocked_mxch;
|
||||
|
||||
vgmstream->meta_type = meta_PC_MXST;
|
||||
if(bits_per_sample == 8)
|
||||
{
|
||||
vgmstream->coding_type = coding_PCM8_U;
|
||||
}
|
||||
else if (bits_per_sample == 16)
|
||||
{
|
||||
vgmstream->coding_type = coding_PCM16LE;
|
||||
}
|
||||
else goto fail;
|
||||
vgmstream->num_samples = sample_count;
|
||||
if(loop_flag)
|
||||
{
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample=vgmstream->num_samples;
|
||||
}
|
||||
/* open the file for reading by each channel */
|
||||
{
|
||||
for (i=0;i<channel_count;i++) {
|
||||
vgmstream->ch[i].streamfile =
|
||||
streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
|
||||
if (!vgmstream->ch[i].streamfile) goto fail;
|
||||
}
|
||||
|
||||
}
|
||||
block_update_mxch(start_offset, vgmstream);
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
//MxSt files ripped from Jukebox.si in Lego Island
|
||||
#include "meta.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "../util.h"
|
||||
|
||||
VGMSTREAM * init_vgmstream_pc_mxst(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
|
||||
int loop_flag=0;
|
||||
int bits_per_sample;
|
||||
int channel_count;
|
||||
int sample_rate,bytes_per_second;
|
||||
long sample_count;
|
||||
int i;
|
||||
off_t file_size;
|
||||
off_t chunk_list_size=-1;
|
||||
off_t start_offset;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("mxst",filename_extension(filename))) goto fail;
|
||||
|
||||
/* looping info not found yet */
|
||||
//loop_flag = get_streamfile_size(streamFile) > 700000;
|
||||
|
||||
/* check MxSt header */
|
||||
if (0x4d785374 != read_32bitBE(0, streamFile)) goto fail;
|
||||
file_size = read_32bitLE(4, streamFile) + 8;
|
||||
if (file_size != get_streamfile_size(streamFile)) goto fail;
|
||||
|
||||
/* read chunks */
|
||||
{
|
||||
off_t MxDa=-1; /* points inside the MxDa chunk */
|
||||
off_t MxCh=-1; /* point at start of the first MxCh chunk */
|
||||
off_t chunk_offset = 8;
|
||||
uint32_t stream_id;
|
||||
while (chunk_offset < file_size)
|
||||
{
|
||||
uint32_t chunk_size = (read_32bitLE(chunk_offset+4, streamFile)+1)/2*2;
|
||||
switch (read_32bitBE(chunk_offset, streamFile))
|
||||
{
|
||||
case 0x4d784f62: /* MxOb */
|
||||
/* not interesting for playback */
|
||||
break;
|
||||
case 0x20574156: /* " WAV" */
|
||||
if (chunk_size == 1)
|
||||
chunk_size = 8;
|
||||
break;
|
||||
case 0x4c495354: /* LIST */
|
||||
{
|
||||
off_t first_item_offset = chunk_offset+0x14;
|
||||
off_t list_chunk_offset = first_item_offset+
|
||||
read_32bitLE(chunk_offset+0x10,streamFile);
|
||||
|
||||
if (read_32bitBE(chunk_offset+0x8,streamFile) == 0x4d784461) /* MxDa */
|
||||
MxDa = first_item_offset;
|
||||
else
|
||||
goto fail;
|
||||
|
||||
if (read_32bitBE(chunk_offset+0xC,streamFile) ==
|
||||
0x4d784368) /* MxCh */
|
||||
{
|
||||
MxCh = list_chunk_offset;
|
||||
chunk_list_size = chunk_size - (list_chunk_offset-(chunk_offset+8));
|
||||
}
|
||||
else
|
||||
goto fail;
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
chunk_offset += 8 + chunk_size;
|
||||
if (chunk_offset > file_size) goto fail;
|
||||
}
|
||||
|
||||
if (MxDa == -1 || MxCh == -1 || chunk_list_size == -1) goto fail;
|
||||
|
||||
/* parse MxDa */
|
||||
{
|
||||
/* ??? */
|
||||
if (0 != read_16bitLE(MxDa+0x00,streamFile)) goto fail;
|
||||
stream_id = read_32bitLE(MxDa+0x2,streamFile);
|
||||
/* First sample (none in MxDa block) */
|
||||
if (-1 != read_32bitLE(MxDa+0x06,streamFile)) goto fail;
|
||||
/* size of format data */
|
||||
if (0x18 != read_32bitLE(MxDa+0x0a,streamFile)) goto fail;
|
||||
/* PCM */
|
||||
if (1 != read_16bitLE(MxDa+0x0e,streamFile)) goto fail;
|
||||
/* channel count */
|
||||
channel_count = read_16bitLE(MxDa+0x10,streamFile);
|
||||
/* only mono known */
|
||||
if (1 != channel_count) goto fail;
|
||||
sample_rate = read_32bitLE(MxDa+0x12,streamFile);
|
||||
bits_per_sample = read_16bitLE(MxDa+0x1c,streamFile);
|
||||
/* bytes per second */
|
||||
bytes_per_second = read_32bitLE(MxDa+0x16,streamFile);
|
||||
if (bits_per_sample/8*channel_count*sample_rate != bytes_per_second) goto fail;
|
||||
/* block align */
|
||||
if (bits_per_sample/8*channel_count !=
|
||||
read_16bitLE(MxDa+0x1a,streamFile)) goto fail;
|
||||
sample_count = read_32bitLE(MxDa+0x1e,streamFile)/(bits_per_sample/8)/channel_count;
|
||||
/* 2c? data offset in normal RIFF WAVE? */
|
||||
if (0x2c != read_32bitLE(MxDa+0x22,streamFile)) goto fail;
|
||||
}
|
||||
|
||||
/* parse through all MxCh for consistency check */
|
||||
{
|
||||
long samples = 0;
|
||||
int split_frames_seen = 0;
|
||||
off_t MxCh_offset = MxCh;
|
||||
while (MxCh_offset < MxCh+chunk_list_size)
|
||||
{
|
||||
uint16_t flags;
|
||||
if (read_32bitBE(MxCh_offset,streamFile)!=0x70616420) /*pad*/
|
||||
{
|
||||
if (read_32bitBE(MxCh_offset,streamFile)!=0x4d784368) /*MxCh*/
|
||||
goto fail;
|
||||
|
||||
flags = read_16bitLE(MxCh_offset+8+0,streamFile);
|
||||
|
||||
if (read_32bitLE(MxCh_offset+8+2,streamFile)!=stream_id)
|
||||
goto fail;
|
||||
|
||||
if (flags & 0x10)
|
||||
{
|
||||
split_frames_seen ++;
|
||||
if (split_frames_seen == 1)
|
||||
{
|
||||
if (read_32bitLE(MxCh_offset+8+6,streamFile)!=(samples*UINT64_C(1000)+sample_rate-1)/sample_rate)
|
||||
goto fail;
|
||||
}
|
||||
else if (split_frames_seen == 2)
|
||||
{
|
||||
if ( read_32bitLE(MxCh_offset+8+0xa,streamFile)!=
|
||||
read_32bitLE(MxCh_offset+4,streamFile)-0xe ) goto fail;
|
||||
split_frames_seen = 0;
|
||||
}
|
||||
else goto fail;
|
||||
}
|
||||
|
||||
if (!(flags & 0x10))
|
||||
{
|
||||
if (split_frames_seen != 0)
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
if (read_32bitLE(MxCh_offset+8+6,streamFile)!=(samples*UINT64_C(1000)+sample_rate-1)/sample_rate)
|
||||
goto fail;
|
||||
|
||||
if ( read_32bitLE(MxCh_offset+8+0xa,streamFile)!=
|
||||
read_32bitLE(MxCh_offset+4,streamFile)-0xe ) goto fail;
|
||||
}
|
||||
samples += (read_32bitLE(MxCh_offset+4,streamFile)-0xe)/(bits_per_sample/8/channel_count);
|
||||
|
||||
}
|
||||
MxCh_offset += 8 + (read_32bitLE(MxCh_offset+4,streamFile)+1)/2*2;
|
||||
if (MxCh_offset > MxCh+chunk_list_size) goto fail;
|
||||
}
|
||||
//printf("samples=%d sample_count=%d\n",samples,sample_count);
|
||||
//samples = (samples * (bits_per_sample/8) * channel_count + 31)/32*32/(bits_per_sample/8)/channel_count;
|
||||
if (samples < sample_count)
|
||||
{
|
||||
sample_count = samples;
|
||||
}
|
||||
if (samples != sample_count) goto fail;
|
||||
}
|
||||
|
||||
start_offset = MxCh;
|
||||
}
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->layout_type = layout_blocked_mxch;
|
||||
|
||||
vgmstream->meta_type = meta_PC_MXST;
|
||||
if(bits_per_sample == 8)
|
||||
{
|
||||
vgmstream->coding_type = coding_PCM8_U;
|
||||
}
|
||||
else if (bits_per_sample == 16)
|
||||
{
|
||||
vgmstream->coding_type = coding_PCM16LE;
|
||||
}
|
||||
else goto fail;
|
||||
vgmstream->num_samples = sample_count;
|
||||
if(loop_flag)
|
||||
{
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample=vgmstream->num_samples;
|
||||
}
|
||||
/* open the file for reading by each channel */
|
||||
{
|
||||
for (i=0;i<channel_count;i++) {
|
||||
vgmstream->ch[i].streamfile =
|
||||
streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
|
||||
if (!vgmstream->ch[i].streamfile) goto fail;
|
||||
}
|
||||
|
||||
}
|
||||
block_update_mxch(start_offset, vgmstream);
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -1,256 +1,256 @@
|
|||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
|
||||
/* Headerless PS-ADPCM
|
||||
* Guesses interleave/channels/loops by testing data and using the file extension for sample rate.
|
||||
* This is an ugly crutch for older sets, use TXTH to properly play headerless data instead. */
|
||||
VGMSTREAM * init_vgmstream_ps_headerless(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset = 0x00;
|
||||
char filename[PATH_LIMIT];
|
||||
|
||||
uint8_t mibBuffer[0x10];
|
||||
uint8_t testBuffer[0x10];
|
||||
|
||||
size_t fileLength;
|
||||
off_t loopStart = 0;
|
||||
off_t loopEnd = 0;
|
||||
off_t interleave = 0;
|
||||
|
||||
off_t readOffset = 0;
|
||||
|
||||
off_t loopStartPoints[0x10] = {0};
|
||||
int loopStartPointsCount=0;
|
||||
off_t loopEndPoints[0x10] = {0};
|
||||
int loopEndPointsCount=0;
|
||||
int loopToEnd=0;
|
||||
int forceNoLoop=0;
|
||||
int gotEmptyLine=0;
|
||||
|
||||
int i, channel_count=0;
|
||||
|
||||
|
||||
/* checks
|
||||
* .mib: common, but many ext-less files are renamed to this.
|
||||
* .mi4: fake .mib to force another sample rate */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("mib",filename_extension(filename)) &&
|
||||
strcasecmp("mi4",filename_extension(filename)))
|
||||
goto fail;
|
||||
|
||||
/* test if raw PS-ADPCM */
|
||||
if (!ps_check_format(streamFile, 0x00, 0x2000))
|
||||
goto fail;
|
||||
|
||||
|
||||
fileLength = get_streamfile_size(streamFile);
|
||||
|
||||
/* Search for interleave value (checking channel starts) and loop points (using PS-ADPCM flags).
|
||||
* Channel start will by 0x0000, 0x0002, 0x0006 followed by 12 zero values.
|
||||
* Interleave value is the offset where those repeat, and channels the number of times.
|
||||
* Loop flags in second byte are: 0x06 = start, 0x03 = end (per channel).
|
||||
* Interleave can be large (up to 0x20000 found so far) and is always a 0x10 multiple value. */
|
||||
readOffset+=(off_t)read_streamfile(mibBuffer,0,0x10,streamFile);
|
||||
mibBuffer[0]=0;
|
||||
{
|
||||
uint8_t doChannelUpdate=1;
|
||||
uint8_t bDoUpdateInterleave=1;
|
||||
|
||||
readOffset=0;
|
||||
do {
|
||||
readOffset+=(off_t)read_streamfile(testBuffer,readOffset,0x10,streamFile);
|
||||
// be sure to point to an interleave value
|
||||
if(readOffset<(int32_t)(fileLength*0.5)) {
|
||||
|
||||
if(memcmp(testBuffer+2, mibBuffer+2,0x0e)) {
|
||||
if(doChannelUpdate) {
|
||||
doChannelUpdate=0;
|
||||
channel_count++;
|
||||
}
|
||||
if(channel_count<2)
|
||||
bDoUpdateInterleave=1;
|
||||
}
|
||||
|
||||
testBuffer[0]=0;
|
||||
if(!memcmp(testBuffer,mibBuffer,0x10)) {
|
||||
gotEmptyLine=1;
|
||||
|
||||
if(bDoUpdateInterleave) {
|
||||
bDoUpdateInterleave=0;
|
||||
interleave=readOffset-0x10;
|
||||
}
|
||||
if(readOffset-0x10 == channel_count*interleave) {
|
||||
doChannelUpdate=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Loop Start ...
|
||||
if(testBuffer[0x01]==0x06) {
|
||||
if(loopStartPointsCount<0x10) {
|
||||
loopStartPoints[loopStartPointsCount] = readOffset-0x10;
|
||||
loopStartPointsCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// Loop End ...
|
||||
if(testBuffer[0x01]==0x03 && testBuffer[0x03]!=0x77) {
|
||||
if(loopEndPointsCount<0x10) {
|
||||
loopEndPoints[loopEndPointsCount] = readOffset;
|
||||
loopEndPointsCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if(testBuffer[0x01]==0x04) {
|
||||
// 0x04 loop points flag can't be with a 0x03 loop points flag
|
||||
if(loopStartPointsCount<0x10) {
|
||||
loopStartPoints[loopStartPointsCount] = readOffset-0x10;
|
||||
loopStartPointsCount++;
|
||||
|
||||
// Loop end value is not set by flags ...
|
||||
// go until end of file
|
||||
loopToEnd=1;
|
||||
}
|
||||
}
|
||||
|
||||
} while (readOffset<((int32_t)fileLength));
|
||||
}
|
||||
|
||||
if(testBuffer[0]==0x0c && testBuffer[1]==0)
|
||||
forceNoLoop=1;
|
||||
|
||||
if(channel_count==0)
|
||||
channel_count=1;
|
||||
|
||||
// Calc Loop Points & Interleave ...
|
||||
if(loopStartPointsCount>=2) {
|
||||
// can't get more then 0x10 loop point !
|
||||
if(loopStartPointsCount<=0x0F) {
|
||||
// Always took the first 2 loop points
|
||||
interleave=loopStartPoints[1]-loopStartPoints[0];
|
||||
loopStart=loopStartPoints[1];
|
||||
|
||||
// Can't be one channel .mib with interleave values
|
||||
if(interleave>0 && channel_count==1)
|
||||
channel_count=2;
|
||||
} else {
|
||||
loopStart=0;
|
||||
}
|
||||
}
|
||||
|
||||
if(loopEndPointsCount>=2) {
|
||||
// can't get more then 0x10 loop point !
|
||||
if(loopEndPointsCount<=0x0F) {
|
||||
// No need to recalculate interleave value ...
|
||||
loopEnd=loopEndPoints[loopEndPointsCount-1];
|
||||
|
||||
// Can't be one channel .mib with interleave values
|
||||
if(channel_count==1)
|
||||
channel_count=2;
|
||||
} else {
|
||||
loopToEnd=0;
|
||||
loopEnd=0;
|
||||
}
|
||||
}
|
||||
|
||||
if (loopToEnd)
|
||||
loopEnd=fileLength;
|
||||
|
||||
if(forceNoLoop)
|
||||
loopEnd=0;
|
||||
|
||||
if(interleave>0x10 && channel_count==1)
|
||||
channel_count=2;
|
||||
|
||||
if(interleave==0)
|
||||
interleave=0x10;
|
||||
|
||||
// further check on channel_count ...
|
||||
if(gotEmptyLine) {
|
||||
int newChannelCount = 0;
|
||||
|
||||
readOffset=0;
|
||||
|
||||
/* count empty lines at interleave = channels */
|
||||
do {
|
||||
newChannelCount++;
|
||||
read_streamfile(testBuffer,readOffset,0x10,streamFile);
|
||||
readOffset+=interleave;
|
||||
} while(!memcmp(testBuffer,mibBuffer,16));
|
||||
|
||||
newChannelCount--;
|
||||
if(newChannelCount>channel_count)
|
||||
channel_count=newChannelCount;
|
||||
}
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,(loopEnd!=0));
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = (channel_count == 1) ? layout_none : layout_interleave;
|
||||
|
||||
vgmstream->interleave_block_size = interleave;
|
||||
|
||||
if(!strcasecmp("mib",filename_extension(filename)))
|
||||
vgmstream->sample_rate = 44100;
|
||||
|
||||
if(!strcasecmp("mi4",filename_extension(filename)))
|
||||
vgmstream->sample_rate = 48000;
|
||||
|
||||
vgmstream->num_samples = (int32_t)(fileLength/16/channel_count*28);
|
||||
|
||||
if(loopEnd!=0) {
|
||||
if(vgmstream->channels==1) {
|
||||
vgmstream->loop_start_sample = loopStart/16*18; //todo 18 instead of 28 probably a bug
|
||||
vgmstream->loop_end_sample = loopEnd/16*28;
|
||||
} else {
|
||||
vgmstream->loop_start_sample = ((((loopStart/vgmstream->interleave_block_size)-1)*vgmstream->interleave_block_size)/16*14*channel_count)/channel_count;
|
||||
if(loopStart%vgmstream->interleave_block_size) {
|
||||
vgmstream->loop_start_sample += (((loopStart%vgmstream->interleave_block_size)-1)/16*14*channel_count);
|
||||
}
|
||||
|
||||
if(loopEnd==fileLength) {
|
||||
vgmstream->loop_end_sample=(loopEnd/16*28)/channel_count;
|
||||
} else {
|
||||
vgmstream->loop_end_sample = ((((loopEnd/vgmstream->interleave_block_size)-1)*vgmstream->interleave_block_size)/16*14*channel_count)/channel_count;
|
||||
if(loopEnd%vgmstream->interleave_block_size) {
|
||||
vgmstream->loop_end_sample += (((loopEnd%vgmstream->interleave_block_size)-1)/16*14*channel_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(loopToEnd) {
|
||||
// try to find if there's no empty line ...
|
||||
int emptySamples=0;
|
||||
|
||||
for(i=0; i<16;i++) {
|
||||
mibBuffer[i]=0; //memset
|
||||
}
|
||||
|
||||
readOffset=fileLength-0x10;
|
||||
do {
|
||||
read_streamfile(testBuffer,readOffset,0x10,streamFile);
|
||||
if(!memcmp(mibBuffer,testBuffer,16)) {
|
||||
emptySamples+=28;
|
||||
}
|
||||
readOffset-=0x10;
|
||||
} while(!memcmp(testBuffer,mibBuffer,16));
|
||||
|
||||
vgmstream->loop_end_sample-=(emptySamples*channel_count);
|
||||
}
|
||||
|
||||
vgmstream->meta_type = meta_PS_HEADERLESS;
|
||||
vgmstream->allow_dual_stereo = 1;
|
||||
|
||||
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"
|
||||
|
||||
|
||||
/* Headerless PS-ADPCM
|
||||
* Guesses interleave/channels/loops by testing data and using the file extension for sample rate.
|
||||
* This is an ugly crutch for older sets, use TXTH to properly play headerless data instead. */
|
||||
VGMSTREAM * init_vgmstream_ps_headerless(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset = 0x00;
|
||||
char filename[PATH_LIMIT];
|
||||
|
||||
uint8_t mibBuffer[0x10];
|
||||
uint8_t testBuffer[0x10];
|
||||
|
||||
size_t fileLength;
|
||||
off_t loopStart = 0;
|
||||
off_t loopEnd = 0;
|
||||
off_t interleave = 0;
|
||||
|
||||
off_t readOffset = 0;
|
||||
|
||||
off_t loopStartPoints[0x10] = {0};
|
||||
int loopStartPointsCount=0;
|
||||
off_t loopEndPoints[0x10] = {0};
|
||||
int loopEndPointsCount=0;
|
||||
int loopToEnd=0;
|
||||
int forceNoLoop=0;
|
||||
int gotEmptyLine=0;
|
||||
|
||||
int i, channel_count=0;
|
||||
|
||||
|
||||
/* checks
|
||||
* .mib: common, but many ext-less files are renamed to this.
|
||||
* .mi4: fake .mib to force another sample rate */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("mib",filename_extension(filename)) &&
|
||||
strcasecmp("mi4",filename_extension(filename)))
|
||||
goto fail;
|
||||
|
||||
/* test if raw PS-ADPCM */
|
||||
if (!ps_check_format(streamFile, 0x00, 0x2000))
|
||||
goto fail;
|
||||
|
||||
|
||||
fileLength = get_streamfile_size(streamFile);
|
||||
|
||||
/* Search for interleave value (checking channel starts) and loop points (using PS-ADPCM flags).
|
||||
* Channel start will by 0x0000, 0x0002, 0x0006 followed by 12 zero values.
|
||||
* Interleave value is the offset where those repeat, and channels the number of times.
|
||||
* Loop flags in second byte are: 0x06 = start, 0x03 = end (per channel).
|
||||
* Interleave can be large (up to 0x20000 found so far) and is always a 0x10 multiple value. */
|
||||
readOffset+=(off_t)read_streamfile(mibBuffer,0,0x10,streamFile);
|
||||
mibBuffer[0]=0;
|
||||
{
|
||||
uint8_t doChannelUpdate=1;
|
||||
uint8_t bDoUpdateInterleave=1;
|
||||
|
||||
readOffset=0;
|
||||
do {
|
||||
readOffset+=(off_t)read_streamfile(testBuffer,readOffset,0x10,streamFile);
|
||||
// be sure to point to an interleave value
|
||||
if(readOffset<(int32_t)(fileLength*0.5)) {
|
||||
|
||||
if(memcmp(testBuffer+2, mibBuffer+2,0x0e)) {
|
||||
if(doChannelUpdate) {
|
||||
doChannelUpdate=0;
|
||||
channel_count++;
|
||||
}
|
||||
if(channel_count<2)
|
||||
bDoUpdateInterleave=1;
|
||||
}
|
||||
|
||||
testBuffer[0]=0;
|
||||
if(!memcmp(testBuffer,mibBuffer,0x10)) {
|
||||
gotEmptyLine=1;
|
||||
|
||||
if(bDoUpdateInterleave) {
|
||||
bDoUpdateInterleave=0;
|
||||
interleave=readOffset-0x10;
|
||||
}
|
||||
if(readOffset-0x10 == channel_count*interleave) {
|
||||
doChannelUpdate=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Loop Start ...
|
||||
if(testBuffer[0x01]==0x06) {
|
||||
if(loopStartPointsCount<0x10) {
|
||||
loopStartPoints[loopStartPointsCount] = readOffset-0x10;
|
||||
loopStartPointsCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// Loop End ...
|
||||
if(testBuffer[0x01]==0x03 && testBuffer[0x03]!=0x77) {
|
||||
if(loopEndPointsCount<0x10) {
|
||||
loopEndPoints[loopEndPointsCount] = readOffset;
|
||||
loopEndPointsCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if(testBuffer[0x01]==0x04) {
|
||||
// 0x04 loop points flag can't be with a 0x03 loop points flag
|
||||
if(loopStartPointsCount<0x10) {
|
||||
loopStartPoints[loopStartPointsCount] = readOffset-0x10;
|
||||
loopStartPointsCount++;
|
||||
|
||||
// Loop end value is not set by flags ...
|
||||
// go until end of file
|
||||
loopToEnd=1;
|
||||
}
|
||||
}
|
||||
|
||||
} while (readOffset<((int32_t)fileLength));
|
||||
}
|
||||
|
||||
if(testBuffer[0]==0x0c && testBuffer[1]==0)
|
||||
forceNoLoop=1;
|
||||
|
||||
if(channel_count==0)
|
||||
channel_count=1;
|
||||
|
||||
// Calc Loop Points & Interleave ...
|
||||
if(loopStartPointsCount>=2) {
|
||||
// can't get more then 0x10 loop point !
|
||||
if(loopStartPointsCount<=0x0F) {
|
||||
// Always took the first 2 loop points
|
||||
interleave=loopStartPoints[1]-loopStartPoints[0];
|
||||
loopStart=loopStartPoints[1];
|
||||
|
||||
// Can't be one channel .mib with interleave values
|
||||
if(interleave>0 && channel_count==1)
|
||||
channel_count=2;
|
||||
} else {
|
||||
loopStart=0;
|
||||
}
|
||||
}
|
||||
|
||||
if(loopEndPointsCount>=2) {
|
||||
// can't get more then 0x10 loop point !
|
||||
if(loopEndPointsCount<=0x0F) {
|
||||
// No need to recalculate interleave value ...
|
||||
loopEnd=loopEndPoints[loopEndPointsCount-1];
|
||||
|
||||
// Can't be one channel .mib with interleave values
|
||||
if(channel_count==1)
|
||||
channel_count=2;
|
||||
} else {
|
||||
loopToEnd=0;
|
||||
loopEnd=0;
|
||||
}
|
||||
}
|
||||
|
||||
if (loopToEnd)
|
||||
loopEnd=fileLength;
|
||||
|
||||
if(forceNoLoop)
|
||||
loopEnd=0;
|
||||
|
||||
if(interleave>0x10 && channel_count==1)
|
||||
channel_count=2;
|
||||
|
||||
if(interleave==0)
|
||||
interleave=0x10;
|
||||
|
||||
// further check on channel_count ...
|
||||
if(gotEmptyLine) {
|
||||
int newChannelCount = 0;
|
||||
|
||||
readOffset=0;
|
||||
|
||||
/* count empty lines at interleave = channels */
|
||||
do {
|
||||
newChannelCount++;
|
||||
read_streamfile(testBuffer,readOffset,0x10,streamFile);
|
||||
readOffset+=interleave;
|
||||
} while(!memcmp(testBuffer,mibBuffer,16));
|
||||
|
||||
newChannelCount--;
|
||||
if(newChannelCount>channel_count)
|
||||
channel_count=newChannelCount;
|
||||
}
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,(loopEnd!=0));
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = (channel_count == 1) ? layout_none : layout_interleave;
|
||||
|
||||
vgmstream->interleave_block_size = interleave;
|
||||
|
||||
if(!strcasecmp("mib",filename_extension(filename)))
|
||||
vgmstream->sample_rate = 44100;
|
||||
|
||||
if(!strcasecmp("mi4",filename_extension(filename)))
|
||||
vgmstream->sample_rate = 48000;
|
||||
|
||||
vgmstream->num_samples = (int32_t)(fileLength/16/channel_count*28);
|
||||
|
||||
if(loopEnd!=0) {
|
||||
if(vgmstream->channels==1) {
|
||||
vgmstream->loop_start_sample = loopStart/16*18; //todo 18 instead of 28 probably a bug
|
||||
vgmstream->loop_end_sample = loopEnd/16*28;
|
||||
} else {
|
||||
vgmstream->loop_start_sample = ((((loopStart/vgmstream->interleave_block_size)-1)*vgmstream->interleave_block_size)/16*14*channel_count)/channel_count;
|
||||
if(loopStart%vgmstream->interleave_block_size) {
|
||||
vgmstream->loop_start_sample += (((loopStart%vgmstream->interleave_block_size)-1)/16*14*channel_count);
|
||||
}
|
||||
|
||||
if(loopEnd==fileLength) {
|
||||
vgmstream->loop_end_sample=(loopEnd/16*28)/channel_count;
|
||||
} else {
|
||||
vgmstream->loop_end_sample = ((((loopEnd/vgmstream->interleave_block_size)-1)*vgmstream->interleave_block_size)/16*14*channel_count)/channel_count;
|
||||
if(loopEnd%vgmstream->interleave_block_size) {
|
||||
vgmstream->loop_end_sample += (((loopEnd%vgmstream->interleave_block_size)-1)/16*14*channel_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(loopToEnd) {
|
||||
// try to find if there's no empty line ...
|
||||
int emptySamples=0;
|
||||
|
||||
for(i=0; i<16;i++) {
|
||||
mibBuffer[i]=0; //memset
|
||||
}
|
||||
|
||||
readOffset=fileLength-0x10;
|
||||
do {
|
||||
read_streamfile(testBuffer,readOffset,0x10,streamFile);
|
||||
if(!memcmp(mibBuffer,testBuffer,16)) {
|
||||
emptySamples+=28;
|
||||
}
|
||||
readOffset-=0x10;
|
||||
} while(!memcmp(testBuffer,mibBuffer,16));
|
||||
|
||||
vgmstream->loop_end_sample-=(emptySamples*channel_count);
|
||||
}
|
||||
|
||||
vgmstream->meta_type = meta_PS_HEADERLESS;
|
||||
vgmstream->allow_dual_stereo = 1;
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -1,38 +1,38 @@
|
|||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* RAW - RAW format is native 44khz PCM file */
|
||||
VGMSTREAM * init_vgmstream_raw_pcm(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag, channel_count;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "raw"))
|
||||
goto fail;
|
||||
|
||||
channel_count = 2;
|
||||
loop_flag = 0;
|
||||
start_offset = 0x00;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_RAW_PCM;
|
||||
vgmstream->sample_rate = 44100;
|
||||
vgmstream->num_samples = pcm_bytes_to_samples(get_streamfile_size(streamFile), channel_count, 16);
|
||||
|
||||
vgmstream->coding_type = coding_PCM16LE;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x02;
|
||||
|
||||
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"
|
||||
|
||||
/* RAW - RAW format is native 44khz PCM file */
|
||||
VGMSTREAM * init_vgmstream_raw_pcm(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag, channel_count;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "raw"))
|
||||
goto fail;
|
||||
|
||||
channel_count = 2;
|
||||
loop_flag = 0;
|
||||
start_offset = 0x00;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_RAW_PCM;
|
||||
vgmstream->sample_rate = 44100;
|
||||
vgmstream->num_samples = pcm_bytes_to_samples(get_streamfile_size(streamFile), channel_count, 16);
|
||||
|
||||
vgmstream->coding_type = coding_PCM16LE;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x02;
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -1,36 +1,36 @@
|
|||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* WAVM - headerless format which can be found on XBOX */
|
||||
VGMSTREAM * init_vgmstream_raw_wavm(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset = 0;
|
||||
int loop_flag, channel_count;
|
||||
|
||||
/* check extension */
|
||||
if (!check_extensions(streamFile,"wavm"))
|
||||
goto fail;
|
||||
|
||||
start_offset = 0;
|
||||
loop_flag = 0;
|
||||
channel_count = 2;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_RAW_WAVM;
|
||||
vgmstream->sample_rate = 44100;
|
||||
vgmstream->num_samples = xbox_ima_bytes_to_samples(get_streamfile_size(streamFile), vgmstream->channels);
|
||||
|
||||
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"
|
||||
|
||||
/* WAVM - headerless format which can be found on XBOX */
|
||||
VGMSTREAM * init_vgmstream_raw_wavm(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset = 0;
|
||||
int loop_flag, channel_count;
|
||||
|
||||
/* check extension */
|
||||
if (!check_extensions(streamFile,"wavm"))
|
||||
goto fail;
|
||||
|
||||
start_offset = 0;
|
||||
loop_flag = 0;
|
||||
channel_count = 2;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_RAW_WAVM;
|
||||
vgmstream->sample_rate = 44100;
|
||||
vgmstream->num_samples = xbox_ima_bytes_to_samples(get_streamfile_size(streamFile), vgmstream->channels);
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -1,53 +1,54 @@
|
|||
#include "meta.h"
|
||||
|
||||
|
||||
/* .seb - Game Arts games [Grandia (PS1), Grandia II/III/X (PS2)] */
|
||||
VGMSTREAM * init_vgmstream_seb(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag, channel_count;
|
||||
|
||||
|
||||
/* checks */
|
||||
/* .seb: found in Grandia II (PS2) .idx */
|
||||
/* .gms: fake? (.stz+idx bigfile without names, except in Grandia II) */
|
||||
if (!check_extensions(streamFile, "seb,gms,"))
|
||||
goto fail;
|
||||
|
||||
channel_count = read_32bitLE(0x00,streamFile);
|
||||
if (channel_count > 2) goto fail; /* mono or stereo */
|
||||
/* 0x08/0c: unknown count, possibly related to looping */
|
||||
|
||||
start_offset = 0x800;
|
||||
|
||||
if (read_32bitLE(0x10,streamFile) > get_streamfile_size(streamFile) || /* loop start offset */
|
||||
read_32bitLE(0x18,streamFile) > get_streamfile_size(streamFile)) /* loop end offset */
|
||||
goto fail;
|
||||
/* in Grandia III sometimes there is a value at 0x24/34 */
|
||||
|
||||
loop_flag = (read_32bitLE(0x20,streamFile) == 0);
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_SEB;
|
||||
vgmstream->sample_rate = read_32bitLE(0x04,streamFile);
|
||||
|
||||
vgmstream->num_samples = read_32bitLE(0x1c,streamFile);
|
||||
vgmstream->loop_start_sample = read_32bitLE(0x14,streamFile);
|
||||
vgmstream->loop_end_sample = read_32bitLE(0x1c,streamFile);
|
||||
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x800;
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
#include "meta.h"
|
||||
|
||||
|
||||
/* .seb - Game Arts games [Grandia (PS1), Grandia II/III/X (PS2)] */
|
||||
VGMSTREAM* init_vgmstream_seb(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag, channels;
|
||||
|
||||
|
||||
/* checks */
|
||||
channels = read_32bitLE(0x00,sf);
|
||||
if (channels > 2)
|
||||
return NULL;
|
||||
// 0x08/0c: unknown count, possibly related to looping
|
||||
|
||||
/* .seb: found in Grandia II (PS2) .idx */
|
||||
/* .gms: fake? (.stz+idx bigfile without names, except in Grandia II) */
|
||||
if (!check_extensions(sf, "seb,gms,"))
|
||||
return NULL;
|
||||
|
||||
start_offset = 0x800;
|
||||
|
||||
if (read_u32le(0x10,sf) > get_streamfile_size(sf) || // loop start offset
|
||||
read_u32le(0x18,sf) > get_streamfile_size(sf)) // loop end offset
|
||||
return NULL;
|
||||
/* in Grandia III sometimes there is a value at 0x24/34 */
|
||||
|
||||
loop_flag = (read_s32le(0x20,sf) == 0);
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channels,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_SEB;
|
||||
vgmstream->sample_rate = read_s32le(0x04,sf);
|
||||
|
||||
vgmstream->num_samples = read_s32le(0x1c,sf);
|
||||
vgmstream->loop_start_sample = read_s32le(0x14,sf);
|
||||
vgmstream->loop_end_sample = read_s32le(0x1c,sf);
|
||||
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x800;
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* SMC+SMH - from Wangan Midnight 1/R (System246) */
|
||||
VGMSTREAM * init_vgmstream_smc_smh(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
STREAMFILE * streamHeader = NULL;
|
||||
off_t start_offset, header_offset = 0;
|
||||
size_t stream_size;
|
||||
int loop_flag = 0, channel_count, sample_rate;
|
||||
int total_subsongs, target_subsong = streamFile->stream_index;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "smc"))
|
||||
goto fail;
|
||||
|
||||
streamHeader = open_streamfile_by_ext(streamFile, "smh");
|
||||
if (!streamHeader) goto fail;
|
||||
|
||||
|
||||
total_subsongs = read_32bitLE(0x00,streamHeader);
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||
|
||||
if (total_subsongs*0x10 + 0x10 != get_streamfile_size(streamHeader))
|
||||
goto fail;
|
||||
|
||||
header_offset = 0x10 + (target_subsong-1)*0x10;
|
||||
|
||||
start_offset = read_32bitLE(header_offset+0x00, streamHeader);
|
||||
stream_size = read_32bitLE(header_offset+0x04, streamHeader);
|
||||
sample_rate = read_32bitLE(header_offset+0x08, streamHeader);
|
||||
/* 0x0c(2): always 0x10, frame size? */
|
||||
channel_count = read_16bitLE(header_offset+0x0e, streamHeader);
|
||||
loop_flag = 0;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->num_samples = ps_bytes_to_samples(stream_size,channel_count);
|
||||
|
||||
vgmstream->num_streams = total_subsongs;
|
||||
vgmstream->stream_size = stream_size;
|
||||
vgmstream->meta_type = meta_SMC_SMH;
|
||||
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = read_32bitLE(0x04, streamHeader);
|
||||
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
|
||||
close_streamfile(streamHeader);
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_streamfile(streamHeader);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
64
Frameworks/vgmstream/vgmstream/src/meta/smh_smc.c
Normal file
64
Frameworks/vgmstream/vgmstream/src/meta/smh_smc.c
Normal file
|
@ -0,0 +1,64 @@
|
|||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* SMH+SMC - from Wangan Midnight 1/R (System246) */
|
||||
VGMSTREAM* init_vgmstream_smh_smc(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
STREAMFILE* sb = NULL;
|
||||
off_t start_offset, header_offset = 0;
|
||||
size_t stream_size;
|
||||
int loop_flag = 0, channels, sample_rate;
|
||||
int total_subsongs, target_subsong = sf->stream_index;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(sf, "smh"))
|
||||
return NULL;
|
||||
|
||||
total_subsongs = read_s32le(0x00,sf);
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||
|
||||
if (total_subsongs * 0x10 + 0x10 != get_streamfile_size(sf))
|
||||
return NULL;
|
||||
|
||||
sb = open_streamfile_by_ext(sf, "smc");
|
||||
if (!sb) goto fail;
|
||||
|
||||
header_offset = 0x10 + (target_subsong - 1) * 0x10;
|
||||
|
||||
start_offset = read_u32le(header_offset+0x00, sf);
|
||||
stream_size = read_u32le(header_offset+0x04, sf);
|
||||
sample_rate = read_u32le(header_offset+0x08, sf);
|
||||
// 0x0c(2): always 0x10, frame size?
|
||||
channels = read_u16le(header_offset+0x0e, sf);
|
||||
loop_flag = 0;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channels, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->num_samples = ps_bytes_to_samples(stream_size, channels);
|
||||
|
||||
vgmstream->num_streams = total_subsongs;
|
||||
vgmstream->stream_size = stream_size;
|
||||
vgmstream->meta_type = meta_SMC_SMH;
|
||||
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = read_32bitLE(0x04, sf);
|
||||
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, sb, start_offset))
|
||||
goto fail;
|
||||
|
||||
close_streamfile(sb);
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_streamfile(sb);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
124
Frameworks/vgmstream/vgmstream/src/meta/srcd.c
Normal file
124
Frameworks/vgmstream/vgmstream/src/meta/srcd.c
Normal file
|
@ -0,0 +1,124 @@
|
|||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* srcd - Capcom RE Engine */
|
||||
VGMSTREAM* init_vgmstream_srcd(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
STREAMFILE* subfile = NULL;
|
||||
off_t start_offset = 0;
|
||||
int loop_flag = 0;
|
||||
int32_t loop_start_sample = 0, loop_end_sample = 0;
|
||||
uint32_t container_type;
|
||||
const char* extension = NULL;
|
||||
VGMSTREAM* (*init_vgmstream_function)(STREAMFILE*) = NULL;
|
||||
|
||||
if (!is_id32be(0x00, sf, "srcd"))
|
||||
return NULL;
|
||||
|
||||
if (!check_extensions(sf, "srcd,asrc,14,21,26,31"))
|
||||
return NULL;
|
||||
|
||||
{
|
||||
enum versions { VERSION_31, VERSION_21_26, VERSION_14, VERSION_UNKNOWN };
|
||||
enum versions ver = VERSION_UNKNOWN;
|
||||
|
||||
//v31 - AJ_AAT
|
||||
if (read_u32le(0x18, sf) > 0x02) {
|
||||
ver = VERSION_31;
|
||||
}
|
||||
//v21 - CAS2
|
||||
else if (read_u32le(0x41, sf) == 0x49) {
|
||||
ver = VERSION_21_26;
|
||||
}
|
||||
//v26 - GTPD
|
||||
else if (read_u32le(0x46, sf) == 0x4E) {
|
||||
ver = VERSION_21_26;
|
||||
}
|
||||
//v14 - CAS
|
||||
else if (read_u8(0x3A, sf) == 0x42) {
|
||||
ver = VERSION_14;
|
||||
}
|
||||
|
||||
switch (ver) {
|
||||
case VERSION_31:
|
||||
loop_flag = read_u8(0x34, sf);
|
||||
loop_start_sample = read_u32le(0x35, sf);
|
||||
loop_end_sample = read_u32le(0x39, sf);
|
||||
break;
|
||||
|
||||
case VERSION_21_26:
|
||||
loop_flag = read_u8(0x2C, sf);
|
||||
loop_start_sample = read_u32le(0x2D, sf);
|
||||
loop_end_sample = read_u32le(0x31, sf);
|
||||
break;
|
||||
|
||||
case VERSION_14:
|
||||
loop_flag = read_u8(0x28, sf);
|
||||
loop_start_sample = read_u32le(0x29, sf);
|
||||
loop_end_sample = read_u32le(0x2D, sf);
|
||||
break;
|
||||
|
||||
default:
|
||||
VGM_LOG("SRCD: Unknown version, disabling loop\n");
|
||||
loop_flag = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
container_type = read_u32be(0x0C, sf);
|
||||
{
|
||||
const off_t scan_start = 0x40;
|
||||
const size_t scan_size = 0x100; //Should be small
|
||||
off_t current_offset;
|
||||
uint32_t magic_to_find = 0;
|
||||
|
||||
if (container_type == get_id32be("wav ")) {
|
||||
magic_to_find = get_id32be("RIFF");
|
||||
} else if (container_type == get_id32be("ogg ")) {
|
||||
magic_to_find = get_id32be("OggS");
|
||||
}
|
||||
|
||||
if (magic_to_find) {
|
||||
for (current_offset = scan_start; current_offset < scan_start + scan_size; current_offset++) {
|
||||
if (read_u32be(current_offset, sf) == magic_to_find) {
|
||||
start_offset = current_offset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (start_offset == 0)
|
||||
goto fail;
|
||||
|
||||
|
||||
/* Select the appropriate init function and extension based on container type */
|
||||
if (container_type == get_id32be("wav ")) {
|
||||
extension = "wav";
|
||||
init_vgmstream_function = init_vgmstream_riff;
|
||||
} else if (container_type == get_id32be("ogg ")) {
|
||||
extension = "ogg";
|
||||
init_vgmstream_function = init_vgmstream_ogg_vorbis;
|
||||
} else {
|
||||
VGM_LOG("SRCD: Codec not recognized");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
subfile = setup_subfile_streamfile(sf, start_offset, get_streamfile_size(sf) - start_offset, extension);
|
||||
if (!subfile) goto fail;
|
||||
|
||||
vgmstream = init_vgmstream_function(subfile);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_SRCD;
|
||||
|
||||
vgmstream_force_loop(vgmstream, loop_flag, loop_start_sample, loop_end_sample);
|
||||
|
||||
close_streamfile(subfile);
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_streamfile(subfile);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
|
@ -1,55 +1,55 @@
|
|||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* WV6 - Gorilla Systems PC games [Spy Kids: Mega Mission Zone (PC), Lilo & Stitch: Hawaiian Adventure (PC)] */
|
||||
VGMSTREAM * init_vgmstream_wv6(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag, channel_count;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "wv6"))
|
||||
goto fail;
|
||||
|
||||
if (read_32bitLE(0x00,streamFile) != get_streamfile_size(streamFile))
|
||||
goto fail;
|
||||
if (read_32bitBE(0x2c,streamFile) != 0x57563620 || /* "WV6 " */
|
||||
read_32bitBE(0x30,streamFile) != 0x494D415F) /* "IMA_" ("WV6 IMA_ADPCM COMPRESSED 16 BIT AUDIO") */
|
||||
goto fail;
|
||||
|
||||
/* 0x54/58/5c/60/6c: unknown (reject to catch possible stereo files, but don't seem to exist) */
|
||||
if (read_32bitLE(0x54,streamFile) != 0x01 ||
|
||||
read_32bitLE(0x58,streamFile) != 0x01 ||
|
||||
read_32bitLE(0x5c,streamFile) != 0x10 ||
|
||||
read_32bitLE(0x68,streamFile) != 0x01 ||
|
||||
read_32bitLE(0x6c,streamFile) != 0x88)
|
||||
goto fail;
|
||||
/* 0x64: PCM size (samples*channels*2) */
|
||||
|
||||
channel_count = 1;
|
||||
loop_flag = 0;
|
||||
start_offset = 0x8c;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = read_32bitLE(0x60, streamFile);
|
||||
vgmstream->num_samples = ima_bytes_to_samples(read_32bitLE(0x88,streamFile), channel_count);
|
||||
|
||||
vgmstream->meta_type = meta_WV6;
|
||||
vgmstream->coding_type = coding_WV6_IMA;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
read_string(vgmstream->stream_name,0x1c+1, 0x04,streamFile);
|
||||
|
||||
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"
|
||||
|
||||
/* WV6 - Gorilla Systems PC games [Spy Kids: Mega Mission Zone (PC), Lilo & Stitch: Hawaiian Adventure (PC)] */
|
||||
VGMSTREAM* init_vgmstream_wv6(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag, channels;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (read_u32le(0x00,sf) != get_streamfile_size(sf))
|
||||
return NULL;
|
||||
// 04: filename
|
||||
if (!is_id32be(0x2c,sf, "WV6 ") || !is_id32be(0x30,sf, "IMA_")) // "WV6 IMA_ADPCM COMPRESSED 16 BIT AUDIO"
|
||||
return NULL;
|
||||
|
||||
if (!check_extensions(sf, "wv6"))
|
||||
return NULL;
|
||||
|
||||
// 0x54/58/5c/60/6c: unknown (reject to catch possible stereo files, but don't seem to exist)
|
||||
if (read_s32le(0x54,sf) != 0x01 ||
|
||||
read_s32le(0x58,sf) != 0x01 ||
|
||||
read_s32le(0x5c,sf) != 0x10 ||
|
||||
read_s32le(0x68,sf) != 0x01 ||
|
||||
read_s32le(0x6c,sf) != 0x88)
|
||||
return NULL;
|
||||
// 0x64: PCM size (samples * channels * 2)
|
||||
|
||||
channels = 1;
|
||||
loop_flag = 0;
|
||||
start_offset = 0x8c;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channels, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = read_s32le(0x60, sf);
|
||||
vgmstream->num_samples = ima_bytes_to_samples(read_u32le(0x88,sf), channels);
|
||||
|
||||
vgmstream->meta_type = meta_WV6;
|
||||
vgmstream->coding_type = coding_WV6_IMA;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
read_string(vgmstream->stream_name, 0x1c + 1, 0x04,sf);
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,sf,start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ enum {
|
|||
VGMSTREAM_MAX_CHANNELS = 64, /* +40ch multilayers */
|
||||
VGMSTREAM_MIN_SAMPLE_RATE = 300, /* 300 is Wwise min */
|
||||
VGMSTREAM_MAX_SAMPLE_RATE = 192000, /* found in some FSB5 */
|
||||
VGMSTREAM_MAX_SUBSONGS = 65535, /* +20000 isn't that uncommon */
|
||||
VGMSTREAM_MAX_SUBSONGS = 90000, /* +20000 isn't that uncommon, known max is 89734 in EA NHL 14 sbs+sbr */
|
||||
VGMSTREAM_MAX_NUM_SAMPLES = 1000000000, /* no ~5h vgm hopefully */
|
||||
};
|
||||
|
||||
|
|
|
@ -317,7 +317,6 @@ init_vgmstream_t init_vgmstream_functions[] = {
|
|||
init_vgmstream_ubi_lyn_container,
|
||||
init_vgmstream_msb_msh,
|
||||
init_vgmstream_txtp,
|
||||
init_vgmstream_smc_smh,
|
||||
init_vgmstream_ppst,
|
||||
init_vgmstream_sps_n1_segmented,
|
||||
init_vgmstream_ubi_bao_pk,
|
||||
|
@ -330,7 +329,6 @@ init_vgmstream_t init_vgmstream_functions[] = {
|
|||
init_vgmstream_xmd,
|
||||
init_vgmstream_cks,
|
||||
init_vgmstream_ckb,
|
||||
init_vgmstream_wv6,
|
||||
init_vgmstream_str_wav,
|
||||
init_vgmstream_wavebatch,
|
||||
init_vgmstream_hd3_bd3,
|
||||
|
@ -368,8 +366,6 @@ init_vgmstream_t init_vgmstream_functions[] = {
|
|||
init_vgmstream_dsp_adpx,
|
||||
init_vgmstream_ogg_opus,
|
||||
init_vgmstream_nus3audio,
|
||||
init_vgmstream_imc,
|
||||
init_vgmstream_imc_container,
|
||||
init_vgmstream_smp,
|
||||
init_vgmstream_gin,
|
||||
init_vgmstream_dsf,
|
||||
|
@ -512,6 +508,8 @@ init_vgmstream_t init_vgmstream_functions[] = {
|
|||
init_vgmstream_audiopkg,
|
||||
init_vgmstream_swar,
|
||||
init_vgmstream_ivb,
|
||||
init_vgmstream_srcd,
|
||||
init_vgmstream_mhwk,
|
||||
|
||||
/* lower priority metas (no clean header identity, somewhat ambiguous, or need extension/companion file to identify) */
|
||||
init_vgmstream_agsc,
|
||||
|
@ -539,6 +537,10 @@ init_vgmstream_t init_vgmstream_functions[] = {
|
|||
init_vgmstream_vai,
|
||||
init_vgmstream_ezw,
|
||||
init_vgmstream_vgs_old,
|
||||
init_vgmstream_imc,
|
||||
init_vgmstream_imc_container,
|
||||
init_vgmstream_wv6,
|
||||
init_vgmstream_smh_smc,
|
||||
/* need companion files */
|
||||
init_vgmstream_pos,
|
||||
init_vgmstream_sli_loops,
|
||||
|
|
|
@ -496,7 +496,7 @@ typedef enum {
|
|||
meta_LSF_N1NJ4N, /* .lsf n1nj4n Fastlane Street Racing (iPhone) */
|
||||
meta_XWAV,
|
||||
meta_RAW_SNDS,
|
||||
meta_HYPERSCAN_KVAG, /* Hyperscan KVAG/BVG */
|
||||
meta_KVAG,
|
||||
meta_PSND,
|
||||
meta_ADP_WILDFIRE,
|
||||
meta_QD_ADP,
|
||||
|
@ -721,6 +721,8 @@ typedef enum {
|
|||
meta_AUDIOPKG,
|
||||
meta_SWAR,
|
||||
meta_IVB,
|
||||
meta_SRCD,
|
||||
meta_MHWK
|
||||
} meta_t;
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue