added MIB / MIB+MIH / MI4 support

git-svn-id: https://vgmstream.svn.sourceforge.net/svnroot/vgmstream@118 51a99a44-fe44-0410-b1ba-c3e57ba2b86b
This commit is contained in:
fastelbja 2008-05-14 20:44:19 +00:00
parent f935a034e0
commit feb99a151c
6 changed files with 191 additions and 3 deletions

View File

@ -254,6 +254,10 @@
RelativePath=".\meta\ps2_int.c"
>
</File>
<File
RelativePath=".\meta\ps2_mib.c"
>
</File>
<File
RelativePath=".\meta\ps2_npsf.c"
>

View File

@ -47,4 +47,6 @@ VGMSTREAM * init_vgmstream_ps2_exst(const char * const filename);
VGMSTREAM * init_vgmstream_ps2_svag(const char * const filename);
VGMSTREAM * init_vgmstream_ps2_mib(const char * const filename);
#endif

171
src/meta/ps2_mib.c Normal file
View File

@ -0,0 +1,171 @@
#include "meta.h"
#include "../util.h"
/* MIB
PS2 MIB format is a headerless format.
The interleave value can be found by checking the body of the data.
The interleave start allways at offset 0 with a int value (which can have
many values : 0x0000, 0x0002, 0x0006 etc...) follow by 12 empty (zero) values.
The interleave value is the offset where you found the same 16 bytes.
The n° of channels can be found by checking each time you found this 16 bytes.
The interleave value can be very "large" (up to 0x20000 found so far) and is allways
a 0x10 multiply value.
The loop values can be found by checking the 'tags' offset (found @ 0x02 each 0x10 bytes).
06 = start of the loop point (can be found for each channel)
03 - end of the loop point (can be found for each channel)
The .MIH header contains all informations about frequency, numbers of channels, interleave
but has, afaik, no loop values.
known extensions : MIB (MIH for the header) MIC (concatenation of MIB+MIH)
Nota : the MIC stuff is not supported here as there is
another MIC format which can be found in Koei Games.
2008-05-14 - Fastelbja : First version ...
*/
VGMSTREAM * init_vgmstream_ps2_mib(const char * const filename) {
VGMSTREAM * vgmstream = NULL;
STREAMFILE * infile = NULL;
STREAMFILE * infileMIH = NULL;
uint8_t mibBuffer[0x10];
uint8_t testBuffer[0x10];
size_t readLength;
size_t fileLength;
off_t loopStart = 0;
off_t loopEnd = 0;
off_t interleave = 0;
off_t readOffset = 0;
size_t bufOffset;
char * filenameMIH;
uint8_t gotMIH=0;
int i, loop_flag, channel_count=1;
/* check extension, case insensitive */
if (strcasecmp("mib",filename_extension(filename)) &&
strcasecmp("mi4",filename_extension(filename))) goto fail;
/* check for .MIH file */
filenameMIH=(char *)malloc(strlen(filename));
if (!filenameMIH) goto fail;
strcpy(filenameMIH,filename);
strcpy(filenameMIH+strlen(filenameMIH)-3,"MIH");
infileMIH = open_streamfile(filenameMIH);
if (infileMIH) gotMIH = 1;
/* Search for interleave value & loop points */
/* Get the first 16 values */
infile=open_streamfile_buffer(filename,0x8000);
if(!infile) goto fail;
fileLength = get_streamfile_size(infile);
readOffset+=read_streamfile(mibBuffer,0,0x10,infile);
do {
readOffset+=read_streamfile(testBuffer,readOffset,0x10,infile);
if(!memcmp(testBuffer,mibBuffer,0x10)) {
if(interleave==0) interleave=readOffset-0x10;
// be sure to point to an interleave value
if((((readOffset-0x10)%interleave)==interleave) || ((readOffset-0x10)==interleave)) {
if (channel_count<6) channel_count++;
}
}
// Loop Start ...
if(testBuffer[0x01]==0x06) {
if(loopStart==0) loopStart = readOffset-0x10;
}
// Loop End ...
if(testBuffer[0x01]==0x03) {
if(loopEnd==0) loopEnd = readOffset-0x10;
}
} while (infile->offset<fileLength);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,(loopStart!=0));
if (!vgmstream) goto fail;
/* fill in the vital statistics */
if(gotMIH) {
// Read stuff from the MIH file
vgmstream->channels = read_32bitLE(0x08,infileMIH);
vgmstream->sample_rate = read_32bitLE(0x0C,infileMIH);
vgmstream->interleave_block_size = read_32bitLE(0x10,infileMIH);
vgmstream->num_samples=((read_32bitLE(0x10,infileMIH)*
(read_32bitLE(0x14,infileMIH)-1)*2)+
((read_32bitLE(0x04,infileMIH)>>8)*2))/16*28/2;
} else {
vgmstream->channels = channel_count;
vgmstream->interleave_block_size = interleave;
if(!strcasecmp("mib",filename_extension(filename)))
vgmstream->sample_rate = 44100;
if(!strcasecmp("mi4",filename_extension(filename)))
vgmstream->sample_rate = 48000;
vgmstream->num_samples = fileLength/16*14;
}
if(loopStart!=0) {
vgmstream->loop_start_sample = ((loopStart/(interleave*channel_count))*interleave)/16*14*channel_count;
vgmstream->loop_start_sample += (loopStart%(interleave*channel_count))/16*14*channel_count;
vgmstream->loop_end_sample = ((loopEnd/(interleave*channel_count))*interleave)/16*14*channel_count;
vgmstream->loop_end_sample += (loopEnd%(interleave*channel_count))/16*14*channel_count;
}
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_interleave;
vgmstream->meta_type = meta_PS2_MIB;
close_streamfile(infile); infile=NULL;
if (gotMIH) {
vgmstream->meta_type = meta_PS2_MIB_MIH;
close_streamfile(infileMIH); infileMIH=NULL;
}
/* open the file for reading by each channel */
{
for (i=0;i<channel_count;i++) {
vgmstream->ch[i].streamfile = open_streamfile_buffer(filename,0x8000);
if (!vgmstream->ch[i].streamfile) goto fail;
vgmstream->ch[i].channel_start_offset=
vgmstream->ch[i].offset=0;
}
}
return vgmstream;
/* clean up anything we may have opened */
fail:
if (infile) close_streamfile(infile);
if (infileMIH) close_streamfile(infileMIH);
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}

View File

@ -15,7 +15,7 @@
* List of functions that will recognize files. These should correspond pretty
* directly to the metadata types
*/
#define INIT_VGMSTREAM_FCNS 22
#define INIT_VGMSTREAM_FCNS 23
VGMSTREAM * (*init_vgmstream_fcns[INIT_VGMSTREAM_FCNS])(const char * const) = {
init_vgmstream_adx, /* 0 */
init_vgmstream_brstm, /* 1 */
@ -39,6 +39,7 @@ VGMSTREAM * (*init_vgmstream_fcns[INIT_VGMSTREAM_FCNS])(const char * const) = {
init_vgmstream_ngc_dsp_stm, /* 19 */
init_vgmstream_ps2_exst, /* 20 */
init_vgmstream_ps2_svag, /* 21 */
init_vgmstream_ps2_mib, /* 22 */
};
@ -606,6 +607,12 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
case meta_PS2_SVAG:
snprintf(temp,TEMPSIZE,"Konami SVAG header");
break;
case meta_PS2_MIB:
snprintf(temp,TEMPSIZE,"assumed MIB Interleaved file by .mib extension");
break;
case meta_PS2_MIB_MIH:
snprintf(temp,TEMPSIZE,"assumed MIB with MIH Info Header file by .mib+.mih extension");
break;
default:
snprintf(temp,TEMPSIZE,"THEY SHOULD HAVE SENT A POET");
}

View File

@ -80,6 +80,8 @@ typedef enum {
meta_PS2_RAW, /* RAW Interleaved Format */
meta_PS2_EXST, /* Shadow of Colossus EXST */
meta_PS2_SVAG, /* Konami SVAG */
meta_PS2_MIB, /* MIB File */
meta_PS2_MIB_MIH, /* MIB File + MIH Header*/
meta_PSX_XA, /* CD-XA with RIFF header */

View File

@ -45,7 +45,7 @@ int fade_samples = 0;
#define EXTENSION_LIST_SIZE 1024
char working_extension_list[EXTENSION_LIST_SIZE] = {0};
#define EXTENSION_COUNT 20
#define EXTENSION_COUNT 22
char * extension_list[EXTENSION_COUNT] = {
"adx\0ADX Audio File (*.ADX)\0",
"afc\0AFC Audio File (*.AFC)\0",
@ -67,6 +67,8 @@ char * extension_list[EXTENSION_COUNT] = {
"int\0PS2 RAW Interleaved PCM (*.INT)\0",
"sts\0PS2 EXST Audio File (*.STS)\0",
"svag\0PS2 SVAG Audio File (*.SVAG)\0",
"mib\0PS2 MIB Audio File (*.MIB)\0",
"mi4\0PS2 MI4 Audio File (*.MI4)\0",
};
/* stubs, we don't do anything fancy yet */