Merge pull request #90 from Thealexbarney/mdsp

Add support for multi-channel Nintendo dsp files
This commit is contained in:
Christopher Snowhill 2017-05-13 18:14:03 -07:00 committed by GitHub
commit 187c161409
4 changed files with 87 additions and 2 deletions

View File

@ -539,6 +539,7 @@ DECLARE_MULTIPLE_FILE_TYPE("MC3 Audio File (*.MC3)", mc3);
DECLARE_MULTIPLE_FILE_TYPE("MCA Audio File (*.MCA)", mca);
DECLARE_MULTIPLE_FILE_TYPE("MCG Audio File (*.MCG)", mcg);
DECLARE_MULTIPLE_FILE_TYPE("MDS Audio File (*.MDS)", mds);
DECLARE_MULTIPLE_FILE_TYPE("MDSP Audio File (*.MDSP)", dsp);
DECLARE_MULTIPLE_FILE_TYPE("PS2 MI4 Audio File (*.MI4)", mi4);
DECLARE_MULTIPLE_FILE_TYPE("PS2 MIB Audio File (*.MIB)", mib);
DECLARE_MULTIPLE_FILE_TYPE("PS2 MIC Audio File (*.MIC)", mic);

View File

@ -27,6 +27,8 @@ VGMSTREAM * init_vgmstream_ngc_adpdtk(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ngc_dsp_std(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ngc_mdsp_std(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ngc_dsp_stm(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ngc_mpdsp(STREAMFILE *streamFile);

View File

@ -24,13 +24,15 @@ struct dsp_header {
uint16_t loop_ps;
int16_t loop_hist1;
int16_t loop_hist2;
int16_t channel_count;
int16_t block_size;
};
/* nonzero on failure */
static int read_dsp_header(struct dsp_header *header, off_t offset, STREAMFILE *file) {
int i;
uint8_t buf[0x4a]; /* usually padded out to 0x60 */
if (read_streamfile(buf, offset, 0x4a, file) != 0x4a) return 1;
uint8_t buf[0x4e]; /* usually padded out to 0x60 */
if (read_streamfile(buf, offset, 0x4e, file) != 0x4e) return 1;
header->sample_count =
get_32bitBE(buf+0x00);
@ -65,6 +67,10 @@ static int read_dsp_header(struct dsp_header *header, off_t offset, STREAMFILE *
get_16bitBE(buf+0x46);
header->loop_hist2 =
get_16bitBE(buf+0x48);
header->channel_count =
get_16bitBE(buf+0x4a);
header->block_size =
get_16bitBE(buf+0x4c);
return 0;
}
@ -175,6 +181,81 @@ fail:
return NULL;
}
/* the standard multi-channel .dsp, as generated by DSPADPCM.exe */
VGMSTREAM * init_vgmstream_ngc_mdsp_std(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
struct dsp_header header;
const off_t header_size = 0x60;
off_t start_offset;
int i, c, channel_count;
/* check extension, case insensitive */
streamFile->get_name(streamFile, filename, sizeof(filename));
if (strcasecmp("dsp", filename_extension(filename)) &&
strcasecmp("mdsp", filename_extension(filename))) goto fail;
if (read_dsp_header(&header, 0, streamFile)) goto fail;
channel_count = header.channel_count==0 ? 1 : header.channel_count;
start_offset = header_size * channel_count;
/* check initial predictor/scale */
if (header.initial_ps != (uint8_t)read_8bit(start_offset, streamFile))
goto fail;
/* check type==0 and gain==0 */
if (header.format || header.gain)
goto fail;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, header.loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
vgmstream->num_samples = header.sample_count;
vgmstream->sample_rate = header.sample_rate;
vgmstream->loop_start_sample = dsp_nibbles_to_samples(
header.loop_start_offset);
vgmstream->loop_end_sample = dsp_nibbles_to_samples(
header.loop_end_offset) + 1;
/* don't know why, but it does happen*/
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_none : layout_interleave;
vgmstream->meta_type = meta_DSP_STD;
vgmstream->interleave_block_size = header.block_size * 8;
for (i = 0; i < channel_count; i++) {
if (read_dsp_header(&header, header_size * i, streamFile)) goto fail;
/* coeffs */
for (c = 0; c < 16; c++)
vgmstream->ch[i].adpcm_coef[c] = header.coef[c];
/* initial history */
/* always 0 that I've ever seen, but for completeness... */
vgmstream->ch[i].adpcm_history1_16 = header.initial_hist1;
vgmstream->ch[i].adpcm_history2_16 = header.initial_hist2;
}
if (!vgmstream_open_stream(vgmstream, streamFile, start_offset))
goto fail;
return vgmstream;
fail:
/* clean up anything we may have opened */
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}
/* Some very simple stereo variants of standard dsp just use the standard header
* twice and add interleave, or just concatenate the channels. We'll support
* them all here.

View File

@ -36,6 +36,7 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = {
init_vgmstream_halpst,
init_vgmstream_rs03,
init_vgmstream_ngc_dsp_std,
init_vgmstream_ngc_mdsp_std,
init_vgmstream_ngc_dsp_csmp,
init_vgmstream_Cstr,
init_vgmstream_gcsw,