mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-29 19:37:30 +01:00
Fix MxSt.
git-svn-id: https://vgmstream.svn.sourceforge.net/svnroot/vgmstream@700 51a99a44-fe44-0410-b1ba-c3e57ba2b86b
This commit is contained in:
parent
c4137c39d2
commit
2ade0dfb62
@ -3,27 +3,20 @@
|
||||
|
||||
//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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
@ -1,72 +1,197 @@
|
||||
//MxSt files ripped from Jukebox.si in Lego Island
|
||||
#include "meta.h"
|
||||
#include "../layout/layout.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 bits_per_sample;
|
||||
int channel_count;
|
||||
int sample_rate,bytes_per_second;
|
||||
long sample_count;
|
||||
int i;
|
||||
off_t j;
|
||||
off_t file_size;
|
||||
off_t chunk_list_size;
|
||||
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;
|
||||
|
||||
/* Always mono files */
|
||||
channel_count=1;
|
||||
//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) 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*1000l+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*1000l+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 = 1;
|
||||
vgmstream->sample_rate = 11025;
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
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))
|
||||
if(bits_per_sample == 8)
|
||||
{
|
||||
vgmstream->coding_type = coding_PCM8_U;
|
||||
bitrate=1;
|
||||
}
|
||||
else
|
||||
else if (bits_per_sample == 16)
|
||||
{
|
||||
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;
|
||||
else goto fail;
|
||||
vgmstream->num_samples = sample_count;
|
||||
if(loop_flag)
|
||||
{
|
||||
vgmstream->loop_start_sample = 0;
|
||||
@ -75,12 +200,14 @@ VGMSTREAM * init_vgmstream_pc_mxst(STREAMFILE *streamFile) {
|
||||
/* open the file for reading by each channel */
|
||||
{
|
||||
for (i=0;i<channel_count;i++) {
|
||||
|
||||
vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,j);
|
||||
vgmstream->ch[i].streamfile =
|
||||
streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
|
||||
if (!vgmstream->ch[i].streamfile) goto fail;
|
||||
}
|
||||
|
||||
}
|
||||
mxch_block_update(start_offset, vgmstream);
|
||||
|
||||
return vgmstream;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user