mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-02-17 11:18:31 +01:00
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:
parent
5d0e2a4fb6
commit
5db0fccc7f
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
29
src/layout/mxch_blocked.c
Normal 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;
|
||||
}
|
||||
}
|
@ -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"
|
||||
>
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
91
src/meta/pc_mxst.c
Normal 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
82
src/meta/pc_sob.c
Normal 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;
|
||||
}
|
@ -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");
|
||||
|
@ -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 */
|
||||
|
@ -183,6 +183,8 @@ gchar *vgmstream_exts [] = {
|
||||
"adpcm",
|
||||
"hwas",
|
||||
"caf",
|
||||
"mxst",
|
||||
"sab"
|
||||
/* terminator */
|
||||
NULL
|
||||
};
|
||||
|
@ -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",
|
||||
|
Loading…
x
Reference in New Issue
Block a user