Lego Island: ripped MxSt files playable, counting samples is slow and brute force

Worms 4: Mayhem: SOB/SAB soundpacks are playable as one stream
Sim City 3000: added second type of header for these xa files.

git-svn-id: https://vgmstream.svn.sourceforge.net/svnroot/vgmstream@683 51a99a44-fe44-0410-b1ba-c3e57ba2b86b
This commit is contained in:
jurassicpieter 2009-09-02 12:18:23 +00:00
parent 5d0e2a4fb6
commit 5db0fccc7f
15 changed files with 257 additions and 2 deletions

View File

@ -229,6 +229,7 @@ etc:
- .str (SDX2 DPCM)
- .um3 (Ogg Vorbis)
- .xa (CD-ROM XA audio)
- .sab (Worms 4 soundpacks)
loop assists:
- .mus (playlist for .acm)

View File

@ -29,5 +29,6 @@ liblayout_la_SOURCES += gsb_blocked.c
liblayout_la_SOURCES += filp_blocked.c
liblayout_la_SOURCES += aax_layout.c
liblayout_la_SOURCES += ivaud_layout.c
liblayout_la_SOURCES += mxch_blocked.c
EXTRA_DIST = layout.h

View File

@ -51,6 +51,9 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM *
switch (vgmstream->layout_type) {
case layout_ast_blocked:
ast_block_update(vgmstream->next_block_offset,vgmstream);
break;
case layout_mxch_blocked:
mxch_block_update(vgmstream->next_block_offset,vgmstream);
break;
case layout_halpst_blocked:
if (vgmstream->next_block_offset>=0)

View File

@ -6,6 +6,8 @@
void ast_block_update(off_t block_ofset, VGMSTREAM * vgmstream);
void mxch_block_update(off_t block_ofset, VGMSTREAM * vgmstream);
void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
void halpst_block_update(off_t block_ofset, VGMSTREAM * vgmstream);

29
src/layout/mxch_blocked.c Normal file
View File

@ -0,0 +1,29 @@
#include "layout.h"
#include "../vgmstream.h"
//MxCh blocked layout as used by Lego Island
void mxch_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
int i;
vgmstream->current_block_offset = block_offset;
vgmstream->next_block_offset = block_offset +
read_32bitLE(block_offset+4,vgmstream->ch[0].streamfile)+4;
if ( 0x4d784368!= read_32bitBE(block_offset,vgmstream->ch[0].streamfile))//ignore non-MxCh blocks
{
vgmstream->current_block_size = 0;
}
else
{
vgmstream->current_block_size = read_32bitLE(block_offset+18, vgmstream->ch[0].streamfile);
//not sure if there are stereo files
for (i=0;i<vgmstream->channels;i++) {
vgmstream->ch[i].offset = vgmstream->current_block_offset + 22+
2*i;
}
}
if(vgmstream->next_block_offset > get_streamfile_size(vgmstream->ch[0].streamfile))
{
vgmstream->current_block_size = 0;
//vgmstream->current_block_size = get_streamfile_size(vgmstream->ch[0].streamfile) - block_offset;
vgmstream->next_block_offset = block_offset+4;
}
}

View File

@ -470,6 +470,14 @@
RelativePath=".\meta\ogg_vorbis_file.c"
>
</File>
<File
RelativePath=".\meta\pc_mxst.c"
>
</File>
<File
RelativePath=".\meta\pc_sob.c"
>
</File>
<File
RelativePath=".\meta\pcm.c"
>
@ -1042,6 +1050,10 @@
RelativePath=".\layout\mus_acm_layout.c"
>
</File>
<File
RelativePath=".\layout\mxch_blocked.c"
>
</File>
<File
RelativePath=".\layout\nolayout.c"
>

View File

@ -164,5 +164,7 @@ libmeta_la_SOURCES += ngc_gcub.c
libmeta_la_SOURCES += maxis_xa.c
libmeta_la_SOURCES += ngc_sck_dsp.c
libmeta_la_SOURCES += apple_caff.c
libmeta_la_SOURCES += pc_mxst.c
libmeta_la_SOURCES += pc_sob.c
EXTRA_DIST = meta.h

View File

@ -14,7 +14,8 @@ VGMSTREAM * init_vgmstream_maxis_xa(STREAMFILE *streamFile) {
if (strcasecmp("xa",filename_extension(filename))) goto fail;
/* check header */
if (read_32bitBE(0x00,streamFile) != 0x58414900) /* "XAI\0" */
if ((read_32bitBE(0x00,streamFile) != 0x58414900)&& /* "XAI\0" */
(read_32bitBE(0x00,streamFile) != 0x58414A00)) /* "XAJ\0" */
goto fail;
loop_flag = 0;
@ -31,6 +32,12 @@ VGMSTREAM * init_vgmstream_maxis_xa(STREAMFILE *streamFile) {
vgmstream->coding_type = coding_MAXIS_ADPCM;
vgmstream->num_samples = read_32bitLE(0x04,streamFile)/2/channel_count;
if (loop_flag) {
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = (read_32bitBE(0x0C,streamFile)-start_offset)/8/channel_count*14;
}
vgmstream->layout_type = layout_none;
vgmstream->meta_type = meta_MAXIS_XA;

View File

@ -407,4 +407,8 @@ VGMSTREAM * init_vgmstream_ngc_sck_dsp(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_apple_caff(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_pc_mxst(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_sab(STREAMFILE* streamFile);
#endif

91
src/meta/pc_mxst.c Normal file
View File

@ -0,0 +1,91 @@
//MxSt files ripped from Jukebox.si in Lego Island
#include "meta.h"
#include "../util.h"
//counts the number of audio data bytes.
//any way to speed this up?
static size_t getNumBytes(off_t offset,STREAMFILE* streamFile) {
off_t j;
size_t siz = 0;
for(j=offset;j<get_streamfile_size(streamFile);j+=2)
{
if(read_32bitBE(j,streamFile)==0x4d784368)//look for MxCh
{
if(read_32bitBE(j+4,streamFile)!=0x4d784368)
siz += read_32bitLE( j + 18, streamFile);
}
}
return siz;
}
VGMSTREAM * init_vgmstream_pc_mxst(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[260];
int loop_flag=0;
int bitrate=2;
int channel_count;
int i;
off_t j;
/* 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;
/* Always mono files */
channel_count=1;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
vgmstream->channels = 1;
vgmstream->sample_rate = 11025;
vgmstream->layout_type = layout_mxch_blocked;
vgmstream->meta_type = meta_PC_MXST;
for(j=0;j<get_streamfile_size(streamFile);j++)
{
if(read_32bitBE(j,streamFile)==0x4D784461)//look for MxDa
break;
}
if(8==read_8bit(40+j,streamFile))
{
vgmstream->coding_type = coding_PCM8_U;
bitrate=1;
}
else
{
vgmstream->coding_type = coding_PCM16LE;
}
if(j==get_streamfile_size(streamFile))
goto fail;
j+=4;
vgmstream->current_block_offset=0;
vgmstream->next_block_offset=j;
vgmstream->num_samples = getNumBytes(j,streamFile) / bitrate / vgmstream->channels;
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,j);
if (!vgmstream->ch[i].streamfile) goto fail;
}
}
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}

82
src/meta/pc_sob.c Normal file
View File

@ -0,0 +1,82 @@
#include "meta.h"
#include "../util.h"
/* SOB/SAB combination as found in Worms 4: Mayhem
they are actually soundpacks, but the audio data is just streamed as one big stream
*/
VGMSTREAM * init_vgmstream_sab(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
STREAMFILE* sob = NULL;
char filename[260];
int i;
int loop_flag, channel_count, numSounds;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("sab",filename_extension(filename))) goto fail;
/* read information from sob file*/
filename[strlen(filename)-2]='o'; //change extension in sob of file
sob = open_stdio_streamfile(filename);
if(!sob) goto fail;
filename[strlen(filename)-2]='a';//change back to original file
if (read_32bitBE(0,streamFile)!=0x43535732)//CSW2 header sab file
{
goto fail;
}
if (read_32bitBE(0,sob)!=0x43544632)//CTF2 header sob file
{
goto fail;
}
numSounds = read_32bitLE(8,sob);
if(numSounds==1)
{//it means it's a single stream and not a voice bank
loop_flag = 1;
}else
{
loop_flag = 0;
}
/* Read channels */
channel_count = read_32bitLE(0x30,sob);
if( (channel_count>2)||(numSounds>1))/* dirty hack for number of channels*/
channel_count = 1;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
//is offset OK. sab files can contain more audio files, but without the sob it's just a long stream of sound effects
vgmstream->current_block_offset=8+32*numSounds;
vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitLE(0x20,streamFile);
vgmstream->coding_type = coding_PCM16LE_int;
vgmstream->num_samples = (int32_t)((get_streamfile_size(streamFile)-vgmstream->current_block_offset)/2/channel_count);
if(loop_flag)
{
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = vgmstream->num_samples;
}
vgmstream->layout_type = layout_none;
vgmstream->meta_type = meta_PC_SOB_SAB;
{
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;
vgmstream->ch[i].channel_start_offset=
vgmstream->ch[i].offset=vgmstream->current_block_offset+2*i;
}
}
close_streamfile(sob);
return vgmstream;
/* clean up anything we may have opened */
fail:
if (sob) close_streamfile(sob);
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}

View File

@ -223,6 +223,9 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = {
init_vgmstream_maxis_xa,
init_vgmstream_ngc_sck_dsp,
init_vgmstream_apple_caff,
init_vgmstream_pc_mxst,
init_vgmstream_sab,
};
#define INIT_VGMSTREAM_FCNS (sizeof(init_vgmstream_fcns)/sizeof(init_vgmstream_fcns[0]))
@ -604,6 +607,7 @@ void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstre
case layout_none:
render_vgmstream_nolayout(buffer,sample_count,vgmstream);
break;
case layout_mxch_blocked:
case layout_ast_blocked:
case layout_halpst_blocked:
case layout_xa_blocked:
@ -1516,6 +1520,9 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
break;
case layout_dtk_interleave:
snprintf(temp,TEMPSIZE,"ADP/DTK nibble interleave");
break;
case layout_mxch_blocked:
snprintf(temp,TEMPSIZE,"MxCh blocked");
break;
case layout_ast_blocked:
snprintf(temp,TEMPSIZE,"AST blocked");
@ -2273,8 +2280,14 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
case meta_CAFF:
snprintf(temp,TEMPSIZE,"Apple Core Audio Format Header");
break;
case meta_PC_MXST:
snprintf(temp,TEMPSIZE,"Lego Island MxSt Header");
break;
case meta_PC_SOB_SAB:
snprintf(temp,TEMPSIZE,"Worms 4: Mayhem SOB/SAB Header");
break;
case meta_MAXIS_XA:
snprintf(temp,TEMPSIZE,"Maxis XAI Header");
snprintf(temp,TEMPSIZE,"Maxis XAI/XAJ Header");
break;
default:
snprintf(temp,TEMPSIZE,"THEY SHOULD HAVE SENT A POET");

View File

@ -134,6 +134,7 @@ typedef enum {
layout_gsb_blocked,
layout_thp_blocked,
layout_filp_blocked,
layout_mxch_blocked,
#if 0
layout_strm_blocked, /* */
@ -377,6 +378,8 @@ typedef enum {
meta_RIFF_WAVE_MWV, /* .mwv RIFF w/ loop data in ctrl chunk pflt */
meta_RIFX_WAVE, /* RIFX, for big-endian WAVs */
meta_RIFX_WAVE_smpl, /* RIFX w/ loop data in smpl chunk */
meta_PC_MXST, /* Lego Island MxSt */
meta_PC_SOB_SAB, /* Worms 4 Mayhem SOB+SAB file */
meta_NWA, /* Visual Art's NWA */
meta_NWA_NWAINFOINI, /* NWA w/ NWAINFO.INI for looping */
meta_NWA_GAMEEXEINI, /* NWA w/ Gameexe.ini for looping */

View File

@ -183,6 +183,8 @@ gchar *vgmstream_exts [] = {
"adpcm",
"hwas",
"caf",
"mxst",
"sab"
/* terminator */
NULL
};

View File

@ -177,6 +177,8 @@ char * extension_list[] = {
"musx\0MUSX Audio File (*.MUSX)\0",
"mss\0MSS Audio File (*.MSS)\0",
"mxst\0MxSt Audio File (*.MxSt)\0",
"ndp\0NDP Audio File (*.NDP)\0",
"npsf\0PS2 NPSF Audio File (*.NPSF)\0",
"nwa\0NWA Audio File (*.NWA)\0",
@ -204,6 +206,7 @@ char * extension_list[] = {
"rwx\0RWX Audio File (*.RWX)\0",
"rxw\0PS2 RXWS File (*.RXW)\0",
"sab\0SAB Audio File (*.SAB)\0",
"sad\0SAD Audio File (*.SAD)\0",
"sap\0SAP Audio File (*.SAP)\0",
"sck\0SCK Audio File (*.SCK)\0",