2011-05-07 13:05:05 +02:00
|
|
|
//#include <stdlib.h>
|
2010-12-03 23:48:51 +01:00
|
|
|
#include "meta.h"
|
|
|
|
#include "../util.h"
|
|
|
|
|
2011-05-07 13:05:05 +02:00
|
|
|
/* MTAF (Metal Gear Solid 3: Snake Eater) */
|
2010-12-03 23:48:51 +01:00
|
|
|
VGMSTREAM * init_vgmstream_ps2_mtaf(STREAMFILE *streamFile) {
|
|
|
|
VGMSTREAM * vgmstream = NULL;
|
|
|
|
char filename[260];
|
2011-05-07 13:05:05 +02:00
|
|
|
off_t start_offset;
|
|
|
|
|
|
|
|
int stream_count;
|
|
|
|
int loop_flag = 1;
|
2010-12-03 23:48:51 +01:00
|
|
|
int channel_count;
|
2011-05-07 13:05:05 +02:00
|
|
|
int32_t loop_start;
|
|
|
|
int32_t loop_end;
|
2010-12-03 23:48:51 +01:00
|
|
|
|
2011-05-07 13:05:05 +02:00
|
|
|
int i;
|
2010-12-03 23:48:51 +01:00
|
|
|
|
|
|
|
/* check extension, case insensitive */
|
|
|
|
streamFile->get_name(streamFile,filename,sizeof(filename));
|
|
|
|
if (strcasecmp("mtaf",filename_extension(filename))) goto fail;
|
|
|
|
|
2011-05-07 13:05:05 +02:00
|
|
|
/* check header */
|
|
|
|
|
|
|
|
// master MTAF header (mostly useless)
|
2010-12-03 23:48:51 +01:00
|
|
|
|
2011-05-08 05:12:45 +02:00
|
|
|
if (read_32bitBE(0, streamFile) != 0x4d544146) // "MTAF"
|
2011-05-07 13:05:05 +02:00
|
|
|
{
|
|
|
|
//fprintf(stderr, "no MTAF header at 0x%08lx\n", cur_off);
|
|
|
|
goto fail;
|
|
|
|
}
|
2010-12-03 23:48:51 +01:00
|
|
|
|
2011-05-07 13:05:05 +02:00
|
|
|
//const uint32_t pseudo_size = readint32(&mtaf_header_buf[4]);
|
|
|
|
|
|
|
|
// check the rest is clear
|
2011-05-08 05:12:45 +02:00
|
|
|
for (i = 0x8; i < 0x20; i++)
|
2011-05-07 13:05:05 +02:00
|
|
|
{
|
|
|
|
if (read_8bit(i, streamFile) != 0)
|
|
|
|
{
|
|
|
|
//fprintf(stderr, "unexpected nonzero in MTAF header at 0x%08lx\n", cur_off+i);
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ignore the rest for now
|
|
|
|
|
|
|
|
// HEAD chunk header
|
|
|
|
|
2011-05-08 05:12:45 +02:00
|
|
|
if (read_32bitBE(0x40, streamFile) != 0x48454144) // "HEAD"
|
2011-05-07 13:05:05 +02:00
|
|
|
{
|
|
|
|
//fprintf(stderr, "no HEAD chunk at 0x%08lx\n", cur_off);
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2011-05-08 05:12:45 +02:00
|
|
|
uint32_t mtaf_head_chunk_size = read_32bitLE(0x44, streamFile);
|
2011-05-07 13:05:05 +02:00
|
|
|
if (mtaf_head_chunk_size != 0xB0)
|
|
|
|
{
|
|
|
|
//fprintf(stderr, "unexpected size for MTAF header at 0x%08lx\n", cur_off);
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-08 05:12:45 +02:00
|
|
|
stream_count = read_8bit(0x61, streamFile);
|
2011-05-07 13:05:05 +02:00
|
|
|
|
|
|
|
// check some standard stuff
|
2011-05-08 05:12:45 +02:00
|
|
|
if ( 0 != read_32bitLE(0x48, streamFile) ||
|
|
|
|
0x7F != read_32bitLE(0x50, streamFile) ||
|
|
|
|
0x40 != read_32bitLE(0x54, streamFile) ||
|
|
|
|
0 != read_16bitLE(0x62, streamFile) ||
|
|
|
|
0 != read_32bitLE(0x6c, streamFile)) // ||
|
2011-05-07 13:05:05 +02:00
|
|
|
//5 != readint32(&mtaf_header_buf[0x68])) ||
|
|
|
|
//(dc.streams==3 ? 12:0) != readint32(&mtaf_header_buf[0x7c]))
|
|
|
|
{
|
|
|
|
//fprintf(stderr, "unexpected header values at 0x%08lx\n", cur_off);
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0 streams should be impossible
|
|
|
|
if (stream_count == 0)
|
|
|
|
{
|
|
|
|
//fprintf(stderr, "0 streams at 0x%08lx\n", cur_off);
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
// check the other stream count indicator
|
2011-05-08 05:12:45 +02:00
|
|
|
if (stream_count*0x10 != read_8bit(0x60, streamFile))
|
2011-05-07 13:05:05 +02:00
|
|
|
{
|
|
|
|
//fprintf(stderr, "secondary stream count mismatch at 0x%08lx\n", cur_off);
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
// maybe this is how to compute channels per stream?
|
|
|
|
// check total channel count
|
2011-05-08 05:12:45 +02:00
|
|
|
if (2*stream_count != read_32bitLE(0x4c, streamFile))
|
2011-05-07 13:05:05 +02:00
|
|
|
{
|
|
|
|
//fprintf(stderr, "total channel count does not match stream count at 0x%08lx\n", cur_off);
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// check loop points as frame counts
|
2011-05-08 05:12:45 +02:00
|
|
|
if (read_32bitLE(0x64, streamFile) != read_32bitLE(0x58, streamFile)/0x100 ||
|
|
|
|
read_32bitLE(0x68, streamFile) != read_32bitLE(0x5c, streamFile)/0x100)
|
2011-05-07 13:05:05 +02:00
|
|
|
{
|
|
|
|
//fprintf(stderr, "loop frame count mismatch at 0x%lx\n", cur_off);
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
// check that rest is clear
|
2011-05-08 05:12:45 +02:00
|
|
|
for (i = 0x78; i < 0xf8; i++)
|
2011-05-07 13:05:05 +02:00
|
|
|
{
|
|
|
|
if (read_8bit(i, streamFile) != 0)
|
|
|
|
{
|
|
|
|
//fprintf(stderr, "unexpected nonzero in HEAD chunk at 0x%lx\n", cur_off+i);
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// check TRKP chunks
|
|
|
|
for (i = 0; i < 16; i++)
|
|
|
|
{
|
2011-05-08 05:12:45 +02:00
|
|
|
if (read_32bitBE(0xf8+0x70*i, streamFile) != 0x54524b50 || // "TRKP"
|
|
|
|
read_32bitLE(0xf8+0x70*i+4, streamFile) != 0x68)
|
2011-05-07 13:05:05 +02:00
|
|
|
{
|
|
|
|
//fprintf(stderr, "missing or unusual TRKP chunk #%d at 0x%lx\n", i, cur_off);
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// check for grand finale, DATA
|
2011-05-08 05:12:45 +02:00
|
|
|
if (read_32bitBE(0x7f8, streamFile) != 0x44415441) // "DATA"
|
2011-05-07 13:05:05 +02:00
|
|
|
{
|
|
|
|
//fprintf(stderr, "missing DATA header at 0x%lx\n", cur_off);
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2011-05-08 05:12:45 +02:00
|
|
|
start_offset = 0x800;
|
2011-05-07 13:05:05 +02:00
|
|
|
|
|
|
|
// seems to always be the case
|
|
|
|
channel_count = 2 * stream_count;
|
|
|
|
|
2011-05-08 05:12:45 +02:00
|
|
|
loop_start = read_32bitLE(0x58, streamFile);
|
|
|
|
loop_end = read_32bitLE(0x5c, streamFile);
|
2011-05-07 13:05:05 +02:00
|
|
|
if (loop_start == loop_end) loop_flag = 0;
|
|
|
|
|
|
|
|
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
2010-12-03 23:48:51 +01:00
|
|
|
if (!vgmstream) goto fail;
|
|
|
|
|
2011-05-07 13:05:05 +02:00
|
|
|
// a guess
|
2010-12-03 23:48:51 +01:00
|
|
|
vgmstream->channels = channel_count;
|
2011-05-07 13:05:05 +02:00
|
|
|
vgmstream->sample_rate = 48000;
|
|
|
|
vgmstream->coding_type = coding_MTAF;
|
2011-05-08 05:12:45 +02:00
|
|
|
vgmstream->num_samples = read_32bitLE(0x5c, streamFile);
|
2011-05-07 13:05:05 +02:00
|
|
|
|
|
|
|
vgmstream->loop_start_sample = loop_start;
|
|
|
|
vgmstream->loop_end_sample = loop_end;
|
|
|
|
|
2011-05-08 05:12:45 +02:00
|
|
|
vgmstream->interleave_block_size = 0x110/2;
|
2010-12-03 23:48:51 +01:00
|
|
|
|
2011-05-08 05:12:45 +02:00
|
|
|
vgmstream->layout_type = layout_interleave;
|
2010-12-03 23:48:51 +01:00
|
|
|
vgmstream->meta_type = meta_PS2_MTAF;
|
|
|
|
|
2011-05-07 13:05:05 +02:00
|
|
|
//const uint32_t pseudo_data_size = readint32(&mtaf_header_buf[4]);
|
2010-12-03 23:48:51 +01:00
|
|
|
|
2011-05-07 13:05:05 +02:00
|
|
|
// TODO: first block
|
2010-12-03 23:48:51 +01:00
|
|
|
|
2011-05-07 13:05:05 +02:00
|
|
|
/* open the file for reading */
|
|
|
|
for (i = 0; i < channel_count; i++) {
|
|
|
|
STREAMFILE * file = streamFile->open(streamFile,filename,vgmstream->interleave_block_size);
|
|
|
|
if (!file) goto fail;
|
|
|
|
vgmstream->ch[i].streamfile = file;
|
2011-05-08 05:12:45 +02:00
|
|
|
vgmstream->ch[i].channel_start_offset = vgmstream->ch[i].offset = start_offset + vgmstream->interleave_block_size*2*(i/2);
|
2010-12-03 23:48:51 +01:00
|
|
|
}
|
2011-05-07 13:05:05 +02:00
|
|
|
|
2010-12-03 23:48:51 +01:00
|
|
|
return vgmstream;
|
|
|
|
|
|
|
|
fail:
|
|
|
|
if (vgmstream) close_vgmstream(vgmstream);
|
|
|
|
return NULL;
|
|
|
|
}
|