2010-03-21 05:23:18 +01:00
|
|
|
#include "meta.h"
|
|
|
|
#include "../layout/layout.h"
|
|
|
|
#include "../util.h"
|
2010-03-23 21:57:12 +01:00
|
|
|
#include "../vgmstream.h"
|
2010-03-21 05:23:18 +01:00
|
|
|
|
|
|
|
/* Namco Bandai's Bandai Namco Sound Format/File (BNSF) */
|
|
|
|
/* similar to RIFX */
|
|
|
|
|
|
|
|
VGMSTREAM * init_vgmstream_bnsf(STREAMFILE *streamFile) {
|
|
|
|
VGMSTREAM * vgmstream = NULL;
|
2013-05-27 05:55:50 +02:00
|
|
|
char filename[PATH_LIMIT];
|
2010-03-21 05:23:18 +01:00
|
|
|
|
|
|
|
off_t file_size = -1;
|
|
|
|
uint32_t riff_size;
|
|
|
|
uint32_t bnsf_form;
|
|
|
|
enum {
|
|
|
|
form_IS14 = UINT32_C(0x49533134), /* IS14 */
|
2015-01-25 06:08:25 +01:00
|
|
|
form_IS22 = UINT32_C(0x49533232), /* IS22 */
|
2010-03-21 05:23:18 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
int channel_count = 0;
|
|
|
|
int sample_count = 0;
|
|
|
|
int sample_rate = 0;
|
|
|
|
int coding_type = -1;
|
|
|
|
off_t start_offset = -1;
|
|
|
|
|
|
|
|
int loop_flag = 0;
|
|
|
|
off_t loop_start = -1;
|
|
|
|
off_t loop_end = -1;
|
|
|
|
uint32_t data_size = 0;
|
|
|
|
uint32_t block_size = 0;
|
|
|
|
uint32_t block_samples = 0;
|
|
|
|
|
|
|
|
int FormatChunkFound = 0;
|
|
|
|
int DataChunkFound = 0;
|
2015-01-25 06:08:25 +01:00
|
|
|
int RiffSizeExtra = 8;
|
2010-03-21 05:23:18 +01:00
|
|
|
|
|
|
|
/* check extension, case insensitive */
|
|
|
|
streamFile->get_name(streamFile,filename,sizeof(filename));
|
|
|
|
if (strcasecmp("bnsf",filename_extension(filename)))
|
|
|
|
{
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check header */
|
|
|
|
if ((uint32_t)read_32bitBE(0,streamFile)!=0x424E5346) /* BNSF */
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
/* check form */
|
|
|
|
bnsf_form = read_32bitBE(8,streamFile);
|
|
|
|
switch (bnsf_form)
|
|
|
|
{
|
|
|
|
#ifdef VGM_USE_G7221
|
|
|
|
case form_IS14:
|
|
|
|
break;
|
2015-01-25 06:08:25 +01:00
|
|
|
#endif
|
|
|
|
#ifdef VGM_USE_G719
|
|
|
|
case form_IS22:
|
|
|
|
RiffSizeExtra = 0;
|
|
|
|
break;
|
2010-03-21 05:23:18 +01:00
|
|
|
#endif
|
|
|
|
default:
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
riff_size = read_32bitBE(4,streamFile);
|
|
|
|
file_size = get_streamfile_size(streamFile);
|
|
|
|
|
|
|
|
/* check for tructated RIFF */
|
2015-01-25 06:08:25 +01:00
|
|
|
if (file_size < riff_size+RiffSizeExtra) goto fail;
|
2010-03-21 05:23:18 +01:00
|
|
|
|
|
|
|
/* read through chunks to verify format and find metadata */
|
|
|
|
{
|
|
|
|
off_t current_chunk = 0xc; /* start with first chunk */
|
|
|
|
|
|
|
|
while (current_chunk < file_size && current_chunk < riff_size+8) {
|
|
|
|
uint32_t chunk_type = read_32bitBE(current_chunk,streamFile);
|
|
|
|
off_t chunk_size = read_32bitBE(current_chunk+4,streamFile);
|
|
|
|
|
|
|
|
if (current_chunk+8+chunk_size > file_size) goto fail;
|
|
|
|
|
|
|
|
switch(chunk_type) {
|
|
|
|
case 0x73666d74: /* "sfmt" */
|
|
|
|
/* only one per file */
|
|
|
|
if (FormatChunkFound) goto fail;
|
|
|
|
FormatChunkFound = 1;
|
|
|
|
|
|
|
|
sample_rate = read_32bitBE(current_chunk+0x0c,streamFile);
|
|
|
|
channel_count = read_16bitBE(current_chunk+0x0a,streamFile);
|
|
|
|
// read_32bitBE(current_chunk+0x10,streamFile); // ?
|
|
|
|
// read_32bitBE(current_chunk+0x14,streamFile); // ?
|
|
|
|
block_size = read_16bitBE(current_chunk+0x18,streamFile);
|
|
|
|
block_samples = read_16bitBE(current_chunk+0x1a,streamFile);
|
|
|
|
|
|
|
|
/* I assume this is still the codec id, but as the codec is
|
|
|
|
specified by the BNSF "form" I've only seen this zero */
|
|
|
|
switch ((uint16_t)read_16bitBE(current_chunk+0x8,streamFile)) {
|
|
|
|
case 0:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 0x73646174: /* sdat */
|
|
|
|
/* at most one per file */
|
|
|
|
if (DataChunkFound) goto fail;
|
|
|
|
DataChunkFound = 1;
|
|
|
|
|
|
|
|
start_offset = current_chunk + 8;
|
|
|
|
data_size = chunk_size;
|
|
|
|
break;
|
|
|
|
case 0x6C6F6F70: /* loop */
|
|
|
|
loop_flag = 1;
|
|
|
|
loop_start =
|
|
|
|
read_32bitBE(current_chunk+8, streamFile);
|
|
|
|
loop_end =
|
|
|
|
read_32bitBE(current_chunk+0xc,streamFile);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* ignorance is bliss */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
current_chunk += 8+chunk_size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!FormatChunkFound || !DataChunkFound) goto fail;
|
|
|
|
|
|
|
|
switch (bnsf_form) {
|
|
|
|
#ifdef VGM_USE_G7221
|
|
|
|
case form_IS14:
|
|
|
|
coding_type = coding_G7221C;
|
|
|
|
sample_count = data_size/block_size*block_samples;
|
|
|
|
|
|
|
|
break;
|
|
|
|
#endif
|
2015-01-25 06:08:25 +01:00
|
|
|
#ifdef VGM_USE_G719
|
|
|
|
case form_IS22:
|
|
|
|
coding_type = coding_G719;
|
|
|
|
sample_count = data_size/block_size*block_samples;
|
|
|
|
|
|
|
|
break;
|
|
|
|
#endif
|
2010-03-21 05:23:18 +01:00
|
|
|
default:
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* build the VGMSTREAM */
|
|
|
|
|
|
|
|
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
|
|
|
if (!vgmstream) goto fail;
|
|
|
|
|
|
|
|
/* fill in the vital statistics */
|
|
|
|
vgmstream->num_samples = sample_count;
|
|
|
|
vgmstream->sample_rate = sample_rate;
|
|
|
|
|
|
|
|
vgmstream->coding_type = coding_type;
|
2010-03-24 21:57:55 +01:00
|
|
|
vgmstream->layout_type = layout_interleave;
|
2010-03-21 05:23:18 +01:00
|
|
|
vgmstream->interleave_block_size = block_size/channel_count;
|
|
|
|
|
|
|
|
if (loop_flag) {
|
|
|
|
vgmstream->loop_start_sample = loop_start;
|
|
|
|
vgmstream->loop_end_sample = loop_end;
|
|
|
|
}
|
|
|
|
vgmstream->meta_type = meta_BNSF;
|
|
|
|
|
2010-03-23 21:57:12 +01:00
|
|
|
#ifdef VGM_USE_G7221
|
|
|
|
if (coding_G7221C == coding_type)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
g7221_codec_data *data;
|
|
|
|
|
|
|
|
/* one data structure per channel */
|
|
|
|
data = malloc(sizeof(g7221_codec_data) * channel_count);
|
|
|
|
if (!data)
|
|
|
|
{
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
memset(data,0,sizeof(g7221_codec_data) * channel_count);
|
|
|
|
vgmstream->codec_data = data;
|
|
|
|
|
|
|
|
for (i = 0; i < channel_count; i++)
|
|
|
|
{
|
|
|
|
/* Siren 14 == 14khz bandwidth */
|
|
|
|
data[i].handle = g7221_init(vgmstream->interleave_block_size, 14000);
|
|
|
|
if (!data[i].handle)
|
|
|
|
{
|
|
|
|
goto fail; /* close_vgmstream is able to clean up */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-01-25 06:08:25 +01:00
|
|
|
#ifdef VGM_USE_G719
|
|
|
|
if (coding_G719 == coding_type)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
g719_codec_data *data;
|
|
|
|
|
|
|
|
/* one data structure per channel */
|
|
|
|
data = malloc(sizeof(g719_codec_data) * channel_count);
|
|
|
|
if (!data)
|
|
|
|
{
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
memset(data,0,sizeof(g719_codec_data) * channel_count);
|
|
|
|
vgmstream->codec_data = data;
|
|
|
|
|
|
|
|
for (i = 0; i < channel_count; i++)
|
|
|
|
{
|
|
|
|
/* Siren 22 == 22khz bandwidth */
|
|
|
|
data[i].handle = g719_init(vgmstream->interleave_block_size);
|
|
|
|
if (!data[i].handle)
|
|
|
|
{
|
|
|
|
goto fail; /* close_vgmstream is able to clean up */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2010-03-21 05:23:18 +01:00
|
|
|
/* open the file, set up each channel */
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,
|
|
|
|
STREAMFILE_DEFAULT_BUFFER_SIZE);
|
|
|
|
if (!vgmstream->ch[0].streamfile) goto fail;
|
|
|
|
|
|
|
|
for (i=0;i<channel_count;i++) {
|
|
|
|
vgmstream->ch[i].streamfile = vgmstream->ch[0].streamfile;
|
|
|
|
vgmstream->ch[i].offset = vgmstream->ch[i].channel_start_offset =
|
|
|
|
start_offset+i*vgmstream->interleave_block_size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return vgmstream;
|
|
|
|
|
|
|
|
/* clean up anything we may have opened */
|
|
|
|
fail:
|
|
|
|
if (vgmstream) close_vgmstream(vgmstream);
|
|
|
|
return NULL;
|
|
|
|
}
|