mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-12 01:30:49 +01:00
Improve XNB [Dragon's Blade (Android)]; add .DA wav; extra exts
This commit is contained in:
parent
e51bafec97
commit
9f90ca9181
@ -40,6 +40,7 @@ VGMSTREAM_DECLARE_FILE_TYPE("AIFCL", aifcl);
|
|||||||
VGMSTREAM_DECLARE_FILE_TYPE("AIX", aix);
|
VGMSTREAM_DECLARE_FILE_TYPE("AIX", aix);
|
||||||
VGMSTREAM_DECLARE_FILE_TYPE("AKB", akb);
|
VGMSTREAM_DECLARE_FILE_TYPE("AKB", akb);
|
||||||
VGMSTREAM_DECLARE_FILE_TYPE("AMTS", amts);
|
VGMSTREAM_DECLARE_FILE_TYPE("AMTS", amts);
|
||||||
|
VGMSTREAM_DECLARE_FILE_TYPE("AO", ao);
|
||||||
VGMSTREAM_DECLARE_FILE_TYPE("AS4", as4);
|
VGMSTREAM_DECLARE_FILE_TYPE("AS4", as4);
|
||||||
VGMSTREAM_DECLARE_FILE_TYPE("ASD", asd);
|
VGMSTREAM_DECLARE_FILE_TYPE("ASD", asd);
|
||||||
VGMSTREAM_DECLARE_FILE_TYPE("ASF", asf);
|
VGMSTREAM_DECLARE_FILE_TYPE("ASF", asf);
|
||||||
@ -92,6 +93,7 @@ VGMSTREAM_DECLARE_FILE_TYPE("CNK", cnk);
|
|||||||
VGMSTREAM_DECLARE_FILE_TYPE("CPS", cps);
|
VGMSTREAM_DECLARE_FILE_TYPE("CPS", cps);
|
||||||
VGMSTREAM_DECLARE_FILE_TYPE("CXS", cxs);
|
VGMSTREAM_DECLARE_FILE_TYPE("CXS", cxs);
|
||||||
|
|
||||||
|
VGMSTREAM_DECLARE_FILE_TYPE("DA", da);
|
||||||
VGMSTREAM_DECLARE_FILE_TYPE("DBM", dbm);
|
VGMSTREAM_DECLARE_FILE_TYPE("DBM", dbm);
|
||||||
VGMSTREAM_DECLARE_FILE_TYPE("DCS", dcs);
|
VGMSTREAM_DECLARE_FILE_TYPE("DCS", dcs);
|
||||||
VGMSTREAM_DECLARE_FILE_TYPE("DDSP", ddsp);
|
VGMSTREAM_DECLARE_FILE_TYPE("DDSP", ddsp);
|
||||||
@ -142,6 +144,7 @@ VGMSTREAM_DECLARE_FILE_TYPE("ILD", ild);
|
|||||||
VGMSTREAM_DECLARE_FILE_TYPE("INT", int);
|
VGMSTREAM_DECLARE_FILE_TYPE("INT", int);
|
||||||
VGMSTREAM_DECLARE_FILE_TYPE("ISD", isd);
|
VGMSTREAM_DECLARE_FILE_TYPE("ISD", isd);
|
||||||
VGMSTREAM_DECLARE_FILE_TYPE("ISWS", isws);
|
VGMSTREAM_DECLARE_FILE_TYPE("ISWS", isws);
|
||||||
|
VGMSTREAM_DECLARE_FILE_TYPE("ITL", itl);
|
||||||
VGMSTREAM_DECLARE_FILE_TYPE("IVAUD", ivaud);
|
VGMSTREAM_DECLARE_FILE_TYPE("IVAUD", ivaud);
|
||||||
VGMSTREAM_DECLARE_FILE_TYPE("IVAG", ivag);
|
VGMSTREAM_DECLARE_FILE_TYPE("IVAG", ivag);
|
||||||
VGMSTREAM_DECLARE_FILE_TYPE("IVB", ivb);
|
VGMSTREAM_DECLARE_FILE_TYPE("IVB", ivb);
|
||||||
|
@ -33,6 +33,7 @@ static const char* extension_list[] = {
|
|||||||
"aix",
|
"aix",
|
||||||
"akb",
|
"akb",
|
||||||
"amts", //fake extension (to be removed)
|
"amts", //fake extension (to be removed)
|
||||||
|
"ao", //txth/reserved [Cloudphobia (PC)]
|
||||||
"as4",
|
"as4",
|
||||||
"asd",
|
"asd",
|
||||||
"asf",
|
"asf",
|
||||||
@ -85,6 +86,7 @@ static const char* extension_list[] = {
|
|||||||
"cps",
|
"cps",
|
||||||
"cxs",
|
"cxs",
|
||||||
|
|
||||||
|
"da",
|
||||||
"dbm",
|
"dbm",
|
||||||
"dcs",
|
"dcs",
|
||||||
"ddsp",
|
"ddsp",
|
||||||
@ -135,6 +137,7 @@ static const char* extension_list[] = {
|
|||||||
"int",
|
"int",
|
||||||
"isd",
|
"isd",
|
||||||
"isws",
|
"isws",
|
||||||
|
"itl", //txth/reserved [Charinko Hero (GC)]
|
||||||
"ivaud",
|
"ivaud",
|
||||||
"ivag",
|
"ivag",
|
||||||
"ivb",
|
"ivb",
|
||||||
@ -660,7 +663,7 @@ static const meta_info meta_info_list[] = {
|
|||||||
{meta_RIFF_WAVE_smpl, "RIFF WAVE header with sample looping info"},
|
{meta_RIFF_WAVE_smpl, "RIFF WAVE header with sample looping info"},
|
||||||
{meta_RIFX_WAVE, "RIFX WAVE header"},
|
{meta_RIFX_WAVE, "RIFX WAVE header"},
|
||||||
{meta_RIFX_WAVE_smpl, "RIFX WAVE header with sample looping info"},
|
{meta_RIFX_WAVE_smpl, "RIFX WAVE header with sample looping info"},
|
||||||
{meta_XNBm, "XNBm header"},
|
{meta_XNB, "Microsoft XNA Game Studio 4.0 header"},
|
||||||
{meta_PCM_SCD, "PCM file with custom header (SCD)"},
|
{meta_PCM_SCD, "PCM file with custom header (SCD)"},
|
||||||
{meta_PCM_PS2, "PCM file with custom header (PS2)"},
|
{meta_PCM_PS2, "PCM file with custom header (PS2)"},
|
||||||
{meta_PS2_RKV, "Legacy of Kain - Blood Omen 2 RKV Header"},
|
{meta_PS2_RKV, "Legacy of Kain - Blood Omen 2 RKV Header"},
|
||||||
|
127
src/meta/riff.c
127
src/meta/riff.c
@ -2,6 +2,7 @@
|
|||||||
#include "../coding/coding.h"
|
#include "../coding/coding.h"
|
||||||
#include "../layout/layout.h"
|
#include "../layout/layout.h"
|
||||||
#include "../util.h"
|
#include "../util.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
/* Resource Interchange File Format */
|
/* Resource Interchange File Format */
|
||||||
|
|
||||||
@ -262,7 +263,8 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
|||||||
/* check extension, case insensitive */
|
/* check extension, case insensitive */
|
||||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||||
if (strcasecmp("wav",filename_extension(filename)) &&
|
if (strcasecmp("wav",filename_extension(filename)) &&
|
||||||
strcasecmp("lwav",filename_extension(filename))
|
strcasecmp("lwav",filename_extension(filename)) &&
|
||||||
|
strcasecmp("da",filename_extension(filename)) /* SD Gundam - Over Galaxian, The Great Battle VI (PS) */
|
||||||
#ifndef VGM_USE_FFMPEG
|
#ifndef VGM_USE_FFMPEG
|
||||||
&& strcasecmp("sgb",filename_extension(filename)) /* SGB has proper support with FFmpeg in sgxd */
|
&& strcasecmp("sgb",filename_extension(filename)) /* SGB has proper support with FFmpeg in sgxd */
|
||||||
#endif
|
#endif
|
||||||
@ -835,79 +837,66 @@ fail:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XNBm (Windows 7 Phone) */
|
//todo move
|
||||||
|
/* XNB - Microsoft XNA Game Studio 4.0 format */
|
||||||
VGMSTREAM * init_vgmstream_xnbm(STREAMFILE *streamFile) {
|
VGMSTREAM * init_vgmstream_xnbm(STREAMFILE *streamFile) {
|
||||||
VGMSTREAM * vgmstream = NULL;
|
VGMSTREAM * vgmstream = NULL;
|
||||||
char filename[PATH_LIMIT];
|
off_t start_offset;
|
||||||
|
int loop_flag = 0, version, flags, num_samples = 0;
|
||||||
|
size_t xnb_size, data_size;
|
||||||
|
|
||||||
struct riff_fmt_chunk fmt;
|
struct riff_fmt_chunk fmt;
|
||||||
|
|
||||||
off_t file_size = -1;
|
|
||||||
int sample_count = 0;
|
|
||||||
off_t start_offset = -1;
|
|
||||||
|
|
||||||
int loop_flag = 0;
|
|
||||||
#if 0
|
|
||||||
long loop_start_ms = -1;
|
|
||||||
long loop_end_ms = -1;
|
|
||||||
off_t loop_start_offset = -1;
|
|
||||||
off_t loop_end_offset = -1;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uint32_t xnbm_size;
|
|
||||||
uint32_t data_size = 0;
|
|
||||||
|
|
||||||
/* check extension, case insensitive */
|
/* check extension, case insensitive */
|
||||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
if ( !check_extensions(streamFile,"xnb"))
|
||||||
if (strcasecmp("xnb",filename_extension(filename)))
|
|
||||||
{
|
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
|
||||||
|
|
||||||
/* check header */
|
/* check header */
|
||||||
if ((uint32_t)read_32bitBE(0,streamFile)!=0x584E426d) /* "XNBm" */
|
if ((read_32bitBE(0,streamFile) & 0xFFFFFF00) != 0x584E4200) /* "XNB" */
|
||||||
goto fail;
|
|
||||||
/* check version? */
|
|
||||||
if ((uint32_t)read_16bitLE(4,streamFile)!=5)
|
|
||||||
goto fail;
|
goto fail;
|
||||||
|
/* 0x04: platform: ‘w’ = Microsoft Windows, ‘m’ = Windows Phone 7, ‘x’ = Xbox 360, 'a' = Android */
|
||||||
|
|
||||||
xnbm_size = read_32bitLE(6,streamFile);
|
version = read_8bit(0x04,streamFile);
|
||||||
file_size = get_streamfile_size(streamFile);
|
if (version != 5) goto fail; /* XNA 4.0 only */
|
||||||
|
|
||||||
/* check for tructated XNBm */
|
flags = read_8bit(0x05,streamFile);
|
||||||
if (file_size < xnbm_size) goto fail;
|
if (flags & 0x80) goto fail; /* compressed with XMemCompress, not public */
|
||||||
|
//if (flags & 0x01) goto fail; /* XMA flag? */
|
||||||
|
|
||||||
/* read through chunks to verify format and find metadata */
|
/* "check for truncated XNB" (???) */
|
||||||
|
xnb_size = read_32bitLE(0x06,streamFile);
|
||||||
|
if (get_streamfile_size(streamFile) < xnb_size) goto fail;
|
||||||
|
|
||||||
|
/* XNB contains "type reader" class references to parse "shared resource" data (can be any implemented filetype) */
|
||||||
{
|
{
|
||||||
off_t current_chunk = 0xa; /* start with first chunk */
|
char reader_name[255+1];
|
||||||
int id_string_len;
|
off_t current_chunk = 0xa;
|
||||||
|
int reader_string_len;
|
||||||
uint32_t fmt_chunk_size;
|
uint32_t fmt_chunk_size;
|
||||||
|
const char * type_sound = "Microsoft.Xna.Framework.Content.SoundEffectReader"; /* partial "fmt" chunk or XMA */
|
||||||
|
//const char * type_song = "Microsoft.Xna.Framework.Content.SongReader"; /* just references a companion .wma */
|
||||||
|
|
||||||
/* flag? count of strings? */
|
/* type reader count, accept only one for now */
|
||||||
if (read_8bit(current_chunk++, streamFile) != 1)
|
if (read_8bit(current_chunk++, streamFile) != 1)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* string length */
|
reader_string_len = read_8bit(current_chunk++, streamFile); /* doesn't count null */
|
||||||
id_string_len = read_8bit(current_chunk ++, streamFile);
|
if (reader_string_len > 255) goto fail;
|
||||||
|
|
||||||
/* skip string */
|
/* check SoundEffect type string */
|
||||||
/* may want to check this ID "Microsoft.Xna.Framework.Content.SoundEffectReader" */
|
if (read_string(reader_name,reader_string_len+1,current_chunk,streamFile) != reader_string_len)
|
||||||
current_chunk += id_string_len;
|
|
||||||
|
|
||||||
/* ???? */
|
|
||||||
if (read_32bitLE(current_chunk, streamFile) != 0)
|
|
||||||
goto fail;
|
goto fail;
|
||||||
current_chunk += 4;
|
if ( strcmp(reader_name, type_sound) != 0 )
|
||||||
|
|
||||||
/* ???? */
|
|
||||||
if (read_8bit(current_chunk ++, streamFile) != 0)
|
|
||||||
goto fail;
|
goto fail;
|
||||||
|
current_chunk += reader_string_len + 1;
|
||||||
|
current_chunk += 4; /* reader version */
|
||||||
|
|
||||||
/* flag? count of chunks? */
|
/* shared resource count */
|
||||||
if (read_8bit(current_chunk++, streamFile) != 1)
|
if (read_8bit(current_chunk++, streamFile) != 1)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* fmt size */
|
/* shared resource: partial "fmt" chunk */
|
||||||
fmt_chunk_size = read_32bitLE(current_chunk, streamFile);
|
fmt_chunk_size = read_32bitLE(current_chunk, streamFile);
|
||||||
current_chunk += 4;
|
current_chunk += 4;
|
||||||
|
|
||||||
@ -918,10 +907,8 @@ VGMSTREAM * init_vgmstream_xnbm(STREAMFILE *streamFile) {
|
|||||||
0, /* sns == false */
|
0, /* sns == false */
|
||||||
0)) /* mwv == false */
|
0)) /* mwv == false */
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
current_chunk += fmt_chunk_size;
|
current_chunk += fmt_chunk_size;
|
||||||
|
|
||||||
/* data size! */
|
|
||||||
data_size = read_32bitLE(current_chunk, streamFile);
|
data_size = read_32bitLE(current_chunk, streamFile);
|
||||||
current_chunk += 4;
|
current_chunk += 4;
|
||||||
|
|
||||||
@ -930,40 +917,40 @@ VGMSTREAM * init_vgmstream_xnbm(STREAMFILE *streamFile) {
|
|||||||
|
|
||||||
switch (fmt.coding_type) {
|
switch (fmt.coding_type) {
|
||||||
case coding_PCM16LE:
|
case coding_PCM16LE:
|
||||||
sample_count = data_size/2/fmt.channel_count;
|
num_samples = pcm_bytes_to_samples(data_size, fmt.channel_count, 16);
|
||||||
break;
|
break;
|
||||||
case coding_PCM8_U_int:
|
case coding_PCM8_U_int:
|
||||||
sample_count = data_size/fmt.channel_count;
|
num_samples = pcm_bytes_to_samples(data_size, fmt.channel_count, 8);
|
||||||
break;
|
break;
|
||||||
case coding_MSADPCM:
|
case coding_MSADPCM:
|
||||||
sample_count = msadpcm_bytes_to_samples(data_size, fmt.block_size, fmt.channel_count);
|
num_samples = msadpcm_bytes_to_samples(data_size, fmt.block_size, fmt.channel_count);
|
||||||
break;
|
break;
|
||||||
case coding_MS_IMA:
|
case coding_MS_IMA:
|
||||||
sample_count = (data_size / fmt.block_size) * (fmt.block_size - 4 * fmt.channel_count) * 2 / fmt.channel_count +
|
num_samples = (data_size / fmt.block_size) * (fmt.block_size - 4 * fmt.channel_count) * 2 / fmt.channel_count +
|
||||||
((data_size % fmt.block_size) ? (data_size % fmt.block_size - 4 * fmt.channel_count) * 2 / fmt.channel_count : 0);
|
((data_size % fmt.block_size) ? (data_size % fmt.block_size - 4 * fmt.channel_count) * 2 / fmt.channel_count : 0);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
VGM_LOG("XNB: unknown codec 0x%x\n", fmt.coding_type);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* build the VGMSTREAM */
|
|
||||||
|
|
||||||
|
/* build the VGMSTREAM */
|
||||||
vgmstream = allocate_vgmstream(fmt.channel_count,loop_flag);
|
vgmstream = allocate_vgmstream(fmt.channel_count,loop_flag);
|
||||||
if (!vgmstream) goto fail;
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
/* fill in the vital statistics */
|
vgmstream->num_samples = num_samples;
|
||||||
vgmstream->num_samples = sample_count;
|
|
||||||
vgmstream->sample_rate = fmt.sample_rate;
|
vgmstream->sample_rate = fmt.sample_rate;
|
||||||
|
|
||||||
|
vgmstream->meta_type = meta_XNB;
|
||||||
vgmstream->coding_type = fmt.coding_type;
|
vgmstream->coding_type = fmt.coding_type;
|
||||||
|
|
||||||
vgmstream->layout_type = layout_none;
|
|
||||||
if (fmt.channel_count > 1) {
|
if (fmt.channel_count > 1) {
|
||||||
switch (fmt.coding_type) {
|
switch (fmt.coding_type) {
|
||||||
case coding_PCM8_U_int:
|
case coding_PCM8_U_int:
|
||||||
case coding_MS_IMA:
|
case coding_MS_IMA:
|
||||||
case coding_MSADPCM:
|
case coding_MSADPCM:
|
||||||
// use layout_none from above
|
vgmstream->layout_type = layout_none;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
vgmstream->layout_type = layout_interleave;
|
vgmstream->layout_type = layout_interleave;
|
||||||
@ -971,40 +958,24 @@ VGMSTREAM * init_vgmstream_xnbm(STREAMFILE *streamFile) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vgmstream->interleave_block_size = fmt.interleave;
|
|
||||||
switch (fmt.coding_type) {
|
switch (fmt.coding_type) {
|
||||||
case coding_MSADPCM:
|
case coding_MSADPCM:
|
||||||
case coding_MS_IMA:
|
case coding_MS_IMA:
|
||||||
// override interleave_block_size with frame size
|
|
||||||
vgmstream->interleave_block_size = fmt.block_size;
|
vgmstream->interleave_block_size = fmt.block_size;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// use interleave from above
|
vgmstream->interleave_block_size = fmt.interleave;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
vgmstream->meta_type = meta_XNBm;
|
|
||||||
|
|
||||||
/* open the file, set up each channel */
|
if ( !vgmstream_open_stream(vgmstream,streamFile,start_offset) )
|
||||||
{
|
goto fail;
|
||||||
int i;
|
|
||||||
|
|
||||||
vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,
|
|
||||||
STREAMFILE_DEFAULT_BUFFER_SIZE);
|
|
||||||
if (!vgmstream->ch[0].streamfile) goto fail;
|
|
||||||
|
|
||||||
for (i=0;i<fmt.channel_count;i++) {
|
|
||||||
vgmstream->ch[i].streamfile = vgmstream->ch[0].streamfile;
|
|
||||||
vgmstream->ch[i].offset = vgmstream->ch[i].channel_start_offset =
|
|
||||||
start_offset+i*fmt.interleave;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return vgmstream;
|
return vgmstream;
|
||||||
|
|
||||||
/* clean up anything we may have opened */
|
|
||||||
fail:
|
fail:
|
||||||
if (vgmstream) close_vgmstream(vgmstream);
|
close_vgmstream(vgmstream);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -479,7 +479,7 @@ typedef enum {
|
|||||||
meta_RIFF_WAVE_SNS, /* .sns RIFF */
|
meta_RIFF_WAVE_SNS, /* .sns RIFF */
|
||||||
meta_RIFX_WAVE, /* RIFX, for big-endian WAVs */
|
meta_RIFX_WAVE, /* RIFX, for big-endian WAVs */
|
||||||
meta_RIFX_WAVE_smpl, /* RIFX w/ loop data in smpl chunk */
|
meta_RIFX_WAVE_smpl, /* RIFX w/ loop data in smpl chunk */
|
||||||
meta_XNBm, /* XNBm, which has a RIFF fmt chunk */
|
meta_XNB, /* XNA Game Studio 4.0 */
|
||||||
meta_PC_MXST, /* Lego Island MxSt */
|
meta_PC_MXST, /* Lego Island MxSt */
|
||||||
meta_PC_SOB_SAB, /* Worms 4 Mayhem SOB+SAB file */
|
meta_PC_SOB_SAB, /* Worms 4 Mayhem SOB+SAB file */
|
||||||
meta_NWA, /* Visual Art's NWA */
|
meta_NWA, /* Visual Art's NWA */
|
||||||
|
Loading…
Reference in New Issue
Block a user