mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-29 00:34:33 +01:00
Clean DSP metas and fix some loop checks
This commit is contained in:
parent
47d2b53c23
commit
452033f14a
@ -24,9 +24,10 @@ struct dsp_header {
|
||||
uint16_t loop_ps;
|
||||
int16_t loop_hist1;
|
||||
int16_t loop_hist2;
|
||||
/* later/mdsp extension */
|
||||
int16_t channel_count;
|
||||
int16_t channel_count; /* DSPADPCM.exe ~v2.7 extension */
|
||||
int16_t block_size;
|
||||
/* padding/reserved up to 0x60 */
|
||||
/* DSPADPCM.exe from GC adds some extra data here (uninitialized MSVC memory?) */
|
||||
};
|
||||
|
||||
/* read the above struct; returns nonzero on failure */
|
||||
@ -34,7 +35,7 @@ static int read_dsp_header_endian(struct dsp_header *header, off_t offset, STREA
|
||||
int32_t (*get_32bit)(uint8_t *) = big_endian ? get_32bitBE : get_32bitLE;
|
||||
int16_t (*get_16bit)(uint8_t *) = big_endian ? get_16bitBE : get_16bitLE;
|
||||
int i;
|
||||
uint8_t buf[0x4e]; /* usually padded out to 0x60 */
|
||||
uint8_t buf[0x4e];
|
||||
|
||||
if (read_streamfile(buf, offset, 0x4e, streamFile) != 0x4e)
|
||||
return 1;
|
||||
@ -131,20 +132,22 @@ static int check_dsp_samples(struct dsp_header* ch_header, int channels) {
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
static int check_dsp_initial_ps(struct dsp_header* ch_header, int channels, STREAMFILE *streamFile, off_t offset, size_t spacing) {
|
||||
static int check_dsp_initial_ps(struct dsp_header* ch_header, int channels, STREAMFILE *streamFile, off_t offset, size_t interleave) {
|
||||
int i;
|
||||
|
||||
/* check initial predictor/scale */
|
||||
for (i = 0; i < channels; i++) {
|
||||
if (ch_header[i].initial_ps != (uint8_t)read_8bit(offset + i*spacing, streamFile))
|
||||
off_t start_offset = offset + i*interleave;
|
||||
if (ch_header[i].initial_ps != (uint8_t)read_8bit(start_offset, streamFile)){
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
static int check_dsp_loop_ps(struct dsp_header* ch_header, int channels, STREAMFILE *streamFile, off_t offset, size_t spacing) {
|
||||
static int check_dsp_loop_ps(struct dsp_header* ch_header, int channels, STREAMFILE *streamFile, off_t offset, size_t interleave) {
|
||||
int i;
|
||||
|
||||
if (!ch_header[0].loop_flag)
|
||||
@ -152,8 +155,13 @@ static int check_dsp_loop_ps(struct dsp_header* ch_header, int channels, STREAMF
|
||||
|
||||
/* check loop predictor/scale */
|
||||
for (i = 0; i < channels; i++) {
|
||||
off_t loop_offset = ch_header[i].loop_start_offset / 16 * 8;
|
||||
if (ch_header[i].loop_ps != (uint8_t)read_8bit(offset + i*spacing + loop_offset,streamFile))
|
||||
off_t loop_offset = ch_header[i].loop_start_offset;
|
||||
if (interleave) {
|
||||
loop_offset = loop_offset / 16 * 8;
|
||||
loop_offset = (loop_offset / interleave * interleave * channels) + (loop_offset % interleave);
|
||||
}
|
||||
|
||||
if (ch_header[i].loop_ps != (uint8_t)read_8bit(offset + i*interleave + loop_offset,streamFile))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@ -172,9 +180,10 @@ typedef struct {
|
||||
|
||||
int force_loop; /* force full loop */
|
||||
int fix_looping; /* fix loop end going past num_samples */
|
||||
int fix_loop_start; /* weird files with bad loop start */
|
||||
int single_header; /* all channels share header, thus totals are off */
|
||||
int ignore_header_agreement; /* sometimes there are minor differences between headers */
|
||||
int ignore_loop_check; /* loop info in header should match data, but sometimes it's weird */
|
||||
int ignore_loop_check; /* loop info in header should match data, but sometimes it's weird */ //todo check if needed anymore
|
||||
|
||||
off_t header_offset;
|
||||
size_t header_spacing;
|
||||
@ -200,6 +209,15 @@ static VGMSTREAM * init_vgmstream_dsp_common(STREAMFILE *streamFile, dsp_meta *d
|
||||
if (!dsp_load_header_endian(ch_header, dspm->channel_count, streamFile,dspm->header_offset,dspm->header_spacing, !dspm->little_endian))
|
||||
goto fail;
|
||||
|
||||
if (dspm->fix_loop_start) {
|
||||
int i;
|
||||
for (i = 0; i < dspm->channel_count; i++) {
|
||||
/* bad/fixed value in loop start */
|
||||
if (ch_header[i].loop_flag)
|
||||
ch_header[i].loop_start_offset = 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
if (!check_dsp_format(ch_header, dspm->channel_count))
|
||||
goto fail;
|
||||
|
||||
@ -274,7 +292,7 @@ VGMSTREAM * init_vgmstream_ngc_dsp_std(STREAMFILE *streamFile) {
|
||||
int i, channel_count;
|
||||
|
||||
/* checks */
|
||||
/* .dsp: standard, .adp: Dr. Muto (GC) mono files */
|
||||
/* .dsp: standard, .adp: Dr. Muto/Battalion Wars (GC) mono files */
|
||||
if (!check_extensions(streamFile, "dsp,adp"))
|
||||
goto fail;
|
||||
|
||||
@ -600,122 +618,47 @@ fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* IDSP with multiple standard DSP headers - from SSB4 (3DS), Tekken Tag Tournament 2 (Wii U) */
|
||||
#define MULTI_IDSP_MAX_CHANNELS 8
|
||||
/* IDSP - Namco header + interleaved dsp [SSB4 (3DS), Tekken Tag Tournament 2 (WiiU)] */
|
||||
VGMSTREAM * init_vgmstream_3ds_idsp(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
dsp_meta dspm = {0};
|
||||
off_t offset;
|
||||
|
||||
off_t idsp_offset = 0;
|
||||
off_t start_offset;
|
||||
off_t interleave;
|
||||
|
||||
struct dsp_header ch_headers[MULTI_IDSP_MAX_CHANNELS];
|
||||
int i, ch;
|
||||
int channel_count;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
//if (check_extensions(streamFile,"idsp,nus3bank")) goto fail;
|
||||
|
||||
/* check header magic */
|
||||
if( read_32bitBE(0x0,streamFile) != 0x49445350 ) /* "IDSP" */
|
||||
{
|
||||
/* try NUS3 format instead */
|
||||
if (read_32bitBE(0,streamFile) != 0x4E555333) goto fail; /* "NUS3" */
|
||||
|
||||
/* Header size */
|
||||
idsp_offset = 0x14 + read_32bitLE( 0x10, streamFile );
|
||||
|
||||
idsp_offset += read_32bitLE( 0x1C, streamFile ) + 8;
|
||||
idsp_offset += read_32bitLE( 0x24, streamFile ) + 8;
|
||||
idsp_offset += read_32bitLE( 0x2C, streamFile ) + 8;
|
||||
idsp_offset += read_32bitLE( 0x34, streamFile ) + 8;
|
||||
idsp_offset += read_32bitLE( 0x3C, streamFile ) + 8;
|
||||
idsp_offset += read_32bitLE( 0x44, streamFile ) + 8;
|
||||
idsp_offset += 8;
|
||||
|
||||
/* check magic */
|
||||
if (read_32bitBE(idsp_offset,streamFile) != 0x49445350) goto fail; /* "IDSP" */
|
||||
}
|
||||
|
||||
channel_count = read_32bitBE(idsp_offset+0x8, streamFile);
|
||||
if (channel_count > MULTI_IDSP_MAX_CHANNELS) goto fail;
|
||||
|
||||
start_offset = read_32bitBE(idsp_offset+0x28,streamFile) + idsp_offset;
|
||||
interleave = 0x10;
|
||||
|
||||
/* read standard dsp header per channel and do some validations */
|
||||
for (ch=0; ch < channel_count; ch++) {
|
||||
/* read 0x60 header per channel */
|
||||
if (read_dsp_header(&ch_headers[ch], idsp_offset + 0x40 + 0x60*ch, streamFile)) goto fail;
|
||||
|
||||
/* check initial values */
|
||||
if (ch_headers[ch].initial_ps != (uint8_t)read_8bit(start_offset + interleave*ch, streamFile)) goto fail;
|
||||
if (ch_headers[ch].format || ch_headers[ch].gain) goto fail;
|
||||
|
||||
/* check for agreement with prev channel*/
|
||||
if (ch > 0 && (
|
||||
ch_headers[ch].sample_count != ch_headers[ch-1].sample_count ||
|
||||
ch_headers[ch].nibble_count != ch_headers[ch-1].nibble_count ||
|
||||
ch_headers[ch].sample_rate != ch_headers[ch-1].sample_rate ||
|
||||
ch_headers[ch].loop_flag != ch_headers[ch-1].loop_flag ||
|
||||
ch_headers[ch].loop_start_offset != ch_headers[ch-1].loop_start_offset ||
|
||||
ch_headers[ch].loop_end_offset != ch_headers[ch-1].loop_end_offset
|
||||
)) goto fail;
|
||||
|
||||
|
||||
#if 0 //this is wrong for >2ch and will fail
|
||||
/* check loop predictor/scale */
|
||||
if (ch_headers[ch].loop_flag) {
|
||||
off_t loop_off;
|
||||
loop_off = ch_headers[ch].loop_start_offset / 8 / channel_count * 8;
|
||||
loop_off = (loop_off / interleave * interleave * channel_count) + (loop_off%interleave);
|
||||
if (ch_headers[ch].loop_ps != (uint8_t)read_8bit(start_offset + loop_off + interleave*ch, streamFile)) goto fail;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
/* check first channel (implicitly all ch) agree with main sample rate */
|
||||
if (ch_headers[0].sample_rate != read_32bitBE(idsp_offset+0xc, streamFile)) goto fail;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,ch_headers[0].loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->num_samples = ch_headers[0].sample_count;
|
||||
vgmstream->sample_rate = ch_headers[0].sample_rate;
|
||||
|
||||
/* TODO: adjust for interleave? */
|
||||
vgmstream->loop_start_sample = dsp_nibbles_to_samples(ch_headers[0].loop_start_offset);
|
||||
vgmstream->loop_end_sample = dsp_nibbles_to_samples(ch_headers[0].loop_end_offset) + 1;
|
||||
/* games will ignore loop_end and use num_samples if going over it
|
||||
* only needed for user-created IDSPs, but it's possible loop_end_sample shouldn't add +1 above */
|
||||
if (vgmstream->loop_end_sample > vgmstream->num_samples)
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = channel_count > 1 ? layout_interleave : layout_none;
|
||||
vgmstream->interleave_block_size = interleave;
|
||||
vgmstream->meta_type = meta_3DS_IDSP;
|
||||
|
||||
|
||||
/* set DSP coefs/history */
|
||||
for (ch=0; ch < channel_count; ch++) {
|
||||
for (i=0;i<16;i++) {
|
||||
vgmstream->ch[ch].adpcm_coef[i] = ch_headers[ch].coef[i];
|
||||
}
|
||||
/* always 0 that I've ever seen, but for completeness... */
|
||||
vgmstream->ch[ch].adpcm_history1_16 = ch_headers[ch].initial_hist1;
|
||||
vgmstream->ch[ch].adpcm_history2_16 = ch_headers[ch].initial_hist2;
|
||||
}
|
||||
|
||||
/* open the file for reading */
|
||||
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "idsp,nus3bank"))
|
||||
goto fail;
|
||||
|
||||
return vgmstream;
|
||||
/* try NUS3BANK container */
|
||||
if (read_32bitBE(0x00,streamFile) == 0x4E555333) { /* "NUS3" */
|
||||
offset = 0x14 + read_32bitLE(0x10, streamFile); /* header size */
|
||||
offset += read_32bitLE(0x1C, streamFile) + 0x08;
|
||||
offset += read_32bitLE(0x24, streamFile) + 0x08;
|
||||
offset += read_32bitLE(0x2C, streamFile) + 0x08;
|
||||
offset += read_32bitLE(0x34, streamFile) + 0x08;
|
||||
offset += read_32bitLE(0x3C, streamFile) + 0x08;
|
||||
offset += read_32bitLE(0x44, streamFile) + 0x08;
|
||||
offset += 0x08;
|
||||
}
|
||||
else {
|
||||
offset = 0x00;
|
||||
}
|
||||
|
||||
if (read_32bitBE(offset,streamFile) != 0x49445350) /* "IDSP" */
|
||||
goto fail;
|
||||
/* 0x0c: sample rate, 0x10: num_samples, 0x14: loop_start_sample, 0x18: loop_start_sample */
|
||||
|
||||
dspm.channel_count = read_32bitBE(offset+0x08, streamFile);
|
||||
dspm.max_channels = 8;
|
||||
/* games do adjust loop_end if bigger than num_samples (only happens in user-created IDSPs) */
|
||||
dspm.fix_looping = 1;
|
||||
|
||||
dspm.header_offset = read_32bitBE(offset+0x20,streamFile) + offset;
|
||||
dspm.header_spacing = read_32bitBE(offset+0x24,streamFile);
|
||||
dspm.start_offset = read_32bitBE(offset+0x28,streamFile) + offset;
|
||||
dspm.interleave = read_32bitBE(offset+0x1c,streamFile); /* usually 0x10 */
|
||||
|
||||
dspm.meta_type = meta_3DS_IDSP;
|
||||
return init_vgmstream_dsp_common(streamFile, &dspm);
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -731,9 +674,6 @@ VGMSTREAM * init_vgmstream_sadb(STREAMFILE *streamFile) {
|
||||
|
||||
dspm.channel_count = read_8bit(0x32, streamFile);
|
||||
dspm.max_channels = 2;
|
||||
//todo: loop check fails unless adjusted:
|
||||
// loop_offset = (loop_offset / spacing * spacing * channels) + (loop_offset % spacing);
|
||||
dspm.ignore_loop_check = 1;
|
||||
|
||||
dspm.header_offset = 0x80;
|
||||
dspm.header_spacing = 0x60;
|
||||
@ -847,112 +787,30 @@ fail:
|
||||
}
|
||||
|
||||
|
||||
/* SWD (found in Conflict - Desert Storm 1 & 2 */
|
||||
/* SWD - PSF chunks + interleaved dsps [Conflict: Desert Storm 1 & 2] */
|
||||
VGMSTREAM * init_vgmstream_ngc_swd(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
off_t start_offset;
|
||||
off_t interleave;
|
||||
dsp_meta dspm = {0};
|
||||
|
||||
struct dsp_header ch0_header, ch1_header;
|
||||
int i;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("swd",filename_extension(filename))) goto fail;
|
||||
|
||||
if (read_dsp_header(&ch0_header, 0x08, streamFile)) goto fail;
|
||||
if (read_dsp_header(&ch1_header, 0x68, streamFile)) goto fail;
|
||||
|
||||
/* check header magic */
|
||||
if (read_32bitBE(0x00,streamFile) != 0x505346D1) /* PSF\0xD1 */
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "swd"))
|
||||
goto fail;
|
||||
|
||||
start_offset = 0xC8;
|
||||
interleave = 0x8;
|
||||
//todo blocked layout when first chunk is 0x50534631 (count + table of 0x0c with offset/sizes)
|
||||
|
||||
#if 0
|
||||
/* check initial predictor/scale */
|
||||
if (ch0_header.initial_ps != (uint8_t)read_8bit(start_offset,streamFile))
|
||||
goto fail;
|
||||
if (ch1_header.initial_ps != (uint8_t)read_8bit(start_offset+interleave,streamFile))
|
||||
goto fail;
|
||||
#endif
|
||||
|
||||
/* check type==0 and gain==0 */
|
||||
if (ch0_header.format || ch0_header.gain ||
|
||||
ch1_header.format || ch1_header.gain)
|
||||
if (read_32bitBE(0x00,streamFile) != 0x505346d1) /* PSF\0xd1 */
|
||||
goto fail;
|
||||
|
||||
/* check for agreement */
|
||||
if (
|
||||
ch0_header.sample_count != ch1_header.sample_count ||
|
||||
ch0_header.nibble_count != ch1_header.nibble_count ||
|
||||
ch0_header.sample_rate != ch1_header.sample_rate ||
|
||||
ch0_header.loop_flag != ch1_header.loop_flag ||
|
||||
ch0_header.loop_start_offset != ch1_header.loop_start_offset ||
|
||||
ch0_header.loop_end_offset != ch1_header.loop_end_offset
|
||||
) goto fail;
|
||||
dspm.channel_count = 2;
|
||||
dspm.max_channels = 2;
|
||||
|
||||
#if 0
|
||||
if (ch0_header.loop_flag) {
|
||||
off_t loop_off;
|
||||
/* check loop predictor/scale */
|
||||
loop_off = ch0_header.loop_start_offset/16*8;
|
||||
loop_off = (loop_off/interleave*interleave*2) + (loop_off%interleave);
|
||||
if (ch0_header.loop_ps != (uint8_t)read_8bit(start_offset+loop_off,streamFile))
|
||||
goto fail;
|
||||
if (ch1_header.loop_ps != (uint8_t)read_8bit(start_offset+loop_off+interleave,streamFile))
|
||||
goto fail;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
|
||||
vgmstream = allocate_vgmstream(2,ch0_header.loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->num_samples = ch0_header.sample_count;
|
||||
vgmstream->sample_rate = ch0_header.sample_rate;
|
||||
|
||||
/* TODO: adjust for interleave? */
|
||||
vgmstream->loop_start_sample = dsp_nibbles_to_samples(ch0_header.loop_start_offset);
|
||||
vgmstream->loop_end_sample = dsp_nibbles_to_samples(ch0_header.loop_end_offset)+1;
|
||||
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = interleave;
|
||||
vgmstream->meta_type = meta_NGC_SWD;
|
||||
|
||||
/* coeffs */
|
||||
for (i=0;i<16;i++) {
|
||||
vgmstream->ch[0].adpcm_coef[i] = ch0_header.coef[i];
|
||||
vgmstream->ch[1].adpcm_coef[i] = ch1_header.coef[i];
|
||||
}
|
||||
|
||||
/* initial history */
|
||||
/* always 0 that I've ever seen, but for completeness... */
|
||||
vgmstream->ch[0].adpcm_history1_16 = ch0_header.initial_hist1;
|
||||
vgmstream->ch[0].adpcm_history2_16 = ch0_header.initial_hist2;
|
||||
vgmstream->ch[1].adpcm_history1_16 = ch1_header.initial_hist1;
|
||||
vgmstream->ch[1].adpcm_history2_16 = ch1_header.initial_hist2;
|
||||
|
||||
vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
vgmstream->ch[1].streamfile = vgmstream->ch[0].streamfile;
|
||||
|
||||
if (!vgmstream->ch[0].streamfile) goto fail;
|
||||
/* open the file for reading */
|
||||
for (i=0;i<2;i++) {
|
||||
vgmstream->ch[i].channel_start_offset=
|
||||
vgmstream->ch[i].offset=start_offset+i*interleave;
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
dspm.header_offset = 0x08;
|
||||
dspm.header_spacing = 0x60;
|
||||
dspm.start_offset = dspm.header_offset + 0x60 * dspm.channel_count;
|
||||
dspm.interleave = 0x08;
|
||||
|
||||
dspm.meta_type = meta_NGC_SWD;
|
||||
return init_vgmstream_dsp_common(streamFile, &dspm);
|
||||
fail:
|
||||
/* clean up anything we may have opened */
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1182,119 +1040,29 @@ fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* .dsp - Ubisoft raw interleaved dsp [Speed Challenge: Jacques Villeneuve's Racing Vision (GC), XIII (GC)] */
|
||||
//todo unusual loop values (set at the end)
|
||||
/* .dsp - Ubisoft interleaved dsp with bad loop start [Speed Challenge: Jacques Villeneuve's Racing Vision (GC), XIII (GC)] */
|
||||
VGMSTREAM * init_vgmstream_dsp_xiii(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
struct dsp_header ch0_header,ch1_header;
|
||||
off_t ch1_header_start, ch2_header_start, ch1_start, ch2_start;
|
||||
size_t interleave;
|
||||
int channel_count;
|
||||
int i;
|
||||
dsp_meta dspm = {0};
|
||||
|
||||
/* check extension */
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "dsp"))
|
||||
goto fail;
|
||||
|
||||
channel_count = 2;
|
||||
|
||||
ch1_header_start = 0x00;
|
||||
ch2_header_start = 0x60;
|
||||
interleave = 0x08;
|
||||
ch1_start = 0xC0;
|
||||
ch2_start = ch1_start + interleave;
|
||||
|
||||
|
||||
/* get DSP headers */
|
||||
if (read_dsp_header(&ch0_header, ch1_header_start, streamFile)) goto fail;
|
||||
if (read_dsp_header(&ch1_header, ch2_header_start, streamFile)) goto fail;
|
||||
|
||||
/* check initial predictor/scale */
|
||||
if (ch0_header.initial_ps != (uint8_t)read_8bit(ch1_start, streamFile))
|
||||
goto fail;
|
||||
if (ch1_header.initial_ps != (uint8_t)read_8bit(ch2_start, streamFile))
|
||||
goto fail;
|
||||
|
||||
/* check type==0 and gain==0 */
|
||||
if (ch0_header.format || ch0_header.gain)
|
||||
goto fail;
|
||||
if (ch1_header.format || ch1_header.gain)
|
||||
goto fail;
|
||||
|
||||
/* check for agreement */
|
||||
if (
|
||||
ch0_header.sample_count != ch1_header.sample_count ||
|
||||
ch0_header.nibble_count != ch1_header.nibble_count ||
|
||||
ch0_header.sample_rate != ch1_header.sample_rate ||
|
||||
ch0_header.loop_flag != ch1_header.loop_flag ||
|
||||
//ch0_header.loop_start_offset != ch1_header.loop_start_offset ||
|
||||
ch0_header.loop_end_offset != ch1_header.loop_end_offset
|
||||
) goto fail;
|
||||
|
||||
if (ch0_header.loop_flag)
|
||||
{
|
||||
off_t loop_off;
|
||||
/* check loop predictor/scale */
|
||||
loop_off = 0x0; //ch0_header.loop_start_offset/16*8;
|
||||
|
||||
if (ch0_header.loop_ps != (uint8_t)read_8bit(ch1_start+loop_off,streamFile))
|
||||
goto fail;
|
||||
if (ch1_header.loop_ps != (uint8_t)read_8bit(ch2_start+loop_off,streamFile))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count, ch1_header.loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->num_samples = ch0_header.sample_count;
|
||||
vgmstream->sample_rate = ch0_header.sample_rate;
|
||||
|
||||
vgmstream->loop_start_sample = 0x0; //dsp_nibbles_to_samples(ch0_header.loop_start_offset);
|
||||
vgmstream->loop_end_sample = dsp_nibbles_to_samples(ch0_header.loop_end_offset)+1;
|
||||
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = interleave;
|
||||
vgmstream->meta_type = meta_DSP_XIII;
|
||||
|
||||
/* coeffs */
|
||||
for (i=0;i<16;i++) {
|
||||
vgmstream->ch[0].adpcm_coef[i] = ch0_header.coef[i];
|
||||
vgmstream->ch[1].adpcm_coef[i] = ch1_header.coef[i];
|
||||
}
|
||||
|
||||
/* initial history */
|
||||
/* always 0 that I've ever seen, but for completeness... */
|
||||
vgmstream->ch[0].adpcm_history1_16 = ch0_header.initial_hist1;
|
||||
vgmstream->ch[0].adpcm_history2_16 = ch0_header.initial_hist2;
|
||||
vgmstream->ch[1].adpcm_history1_16 = ch1_header.initial_hist1;
|
||||
vgmstream->ch[1].adpcm_history2_16 = ch1_header.initial_hist2;
|
||||
|
||||
/* open the file for reading */
|
||||
vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!vgmstream->ch[0].streamfile)
|
||||
goto fail;
|
||||
vgmstream->ch[0].channel_start_offset = vgmstream->ch[0].offset=ch1_start;
|
||||
|
||||
vgmstream->ch[1].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!vgmstream->ch[1].streamfile)
|
||||
goto fail;
|
||||
vgmstream->ch[1].channel_start_offset = vgmstream->ch[1].offset=ch2_start;
|
||||
|
||||
return vgmstream;
|
||||
dspm.channel_count = 2;
|
||||
dspm.max_channels = 2;
|
||||
dspm.fix_loop_start = 1; /* loop flag but strange loop start instead of 0 (maybe shouldn't loop) */
|
||||
|
||||
dspm.header_offset = 0x00;
|
||||
dspm.header_spacing = 0x60;
|
||||
dspm.start_offset = dspm.header_offset + dspm.header_spacing * dspm.channel_count;
|
||||
dspm.interleave = 0x08;
|
||||
|
||||
dspm.meta_type = meta_DSP_XIII;
|
||||
return init_vgmstream_dsp_common(streamFile, &dspm);
|
||||
fail:
|
||||
/* clean up anything we may have opened */
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* NPD - Icon Games header + subinterleaved DSPs [Vertigo (Wii), Build n' Race (Wii)] */
|
||||
VGMSTREAM * init_vgmstream_wii_ndp(STREAMFILE *streamFile) {
|
||||
dsp_meta dspm = {0};
|
||||
|
Loading…
Reference in New Issue
Block a user